blob: f95ecdfc6f2f00e0bf13c6ef0f41dabf939c9ae3 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000231 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000358 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000368 JSObject::NormalizeProperties(
369 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000387 result = JSObject::SetOwnElement(
388 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 Handle<String> name(String::cast(*key));
391 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000392 result = JSObject::SetLocalPropertyIgnoreAttributes(
393 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 } else if (key->ToArrayIndex(&element_index)) {
396 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000397 result = JSObject::SetOwnElement(
398 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 } else {
400 // Non-uint32 number.
401 ASSERT(key->IsNumber());
402 double num = key->Number();
403 char arr[100];
404 Vector<char> buffer(arr, ARRAY_SIZE(arr));
405 const char* str = DoubleToCString(num, buffer);
406 Handle<String> name =
407 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000408 result = JSObject::SetLocalPropertyIgnoreAttributes(
409 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 // If setting the property on the boilerplate throws an
412 // exception, the exception is converted to an empty handle in
413 // the handle based operations. In that case, we need to
414 // convert back to an exception.
415 if (result.is_null()) return result;
416 }
417
418 // Transform to fast properties if necessary. For object literals with
419 // containing function literals we defer this operation until after all
420 // computed properties have been assigned so that we can generate
421 // constant function properties.
422 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000423 JSObject::TransformToFastProperties(
424 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 }
426
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000428}
429
430
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000431static const int kSmiOnlyLiteralMinimumLength = 1024;
432
433
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000434Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436 Handle<FixedArray> literals,
437 Handle<FixedArray> elements) {
438 // Create the JSArray.
439 Handle<JSFunction> constructor(
440 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000441 Handle<JSArray> object =
442 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000444 ElementsKind constant_elements_kind =
445 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
446 Handle<FixedArrayBase> constant_elements_values(
447 FixedArrayBase::cast(elements->get(1)));
448
449 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
450 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
451 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
452 constant_elements_kind > object->GetElementsKind();
453
454 if (!FLAG_smi_only_arrays &&
455 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
456 constant_elements_kind != object->GetElementsKind()) {
457 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000458 }
459
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000460 // If the ElementsKind of the constant values of the array literal are less
461 // specific than the ElementsKind of the boilerplate array object, change the
462 // boilerplate array object's map to reflect that kind.
463 if (allow_literal_kind_transition) {
464 Handle<Map> transitioned_array_map =
465 isolate->factory()->GetElementsTransitionMap(object,
466 constant_elements_kind);
467 object->set_map(*transitioned_array_map);
468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 Handle<FixedArrayBase> copied_elements_values;
471 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
472 ASSERT(FLAG_smi_only_arrays);
473 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
474 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000475 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
477 constant_elements_kind == FAST_ELEMENTS);
478 const bool is_cow =
479 (constant_elements_values->map() ==
480 isolate->heap()->fixed_cow_array_map());
481 if (is_cow) {
482 copied_elements_values = constant_elements_values;
483#if DEBUG
484 Handle<FixedArray> fixed_array_values =
485 Handle<FixedArray>::cast(copied_elements_values);
486 for (int i = 0; i < fixed_array_values->length(); i++) {
487 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
488 }
489#endif
490 } else {
491 Handle<FixedArray> fixed_array_values =
492 Handle<FixedArray>::cast(constant_elements_values);
493 Handle<FixedArray> fixed_array_values_copy =
494 isolate->factory()->CopyFixedArray(fixed_array_values);
495 copied_elements_values = fixed_array_values_copy;
496 for (int i = 0; i < fixed_array_values->length(); i++) {
497 Object* current = fixed_array_values->get(i);
498 if (current->IsFixedArray()) {
499 // The value contains the constant_properties of a
500 // simple object or array literal.
501 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
502 Handle<Object> result =
503 CreateLiteralBoilerplate(isolate, literals, fa);
504 if (result.is_null()) return result;
505 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000508 }
509 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000510 object->set_elements(*copied_elements_values);
511 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 return object;
513}
514
515
516static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 Handle<FixedArray> literals,
519 Handle<FixedArray> array) {
520 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 true,
528 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000529 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 return CreateObjectLiteralBoilerplate(isolate,
531 literals,
532 elements,
533 false,
534 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000536 return Runtime::CreateArrayLiteralBoilerplate(
537 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 default:
539 UNREACHABLE();
540 return Handle<Object>::null();
541 }
542}
543
544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000549 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
553 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateObjectLiteralBoilerplate(isolate,
559 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 should_have_fast_elements,
562 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 if (boilerplate.is_null()) return Failure::Exception();
564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *boilerplate);
566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568}
569
570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000571RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000575 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
579 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580
581 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 Handle<Object> boilerplate(literals->get(literals_index), isolate);
583 if (*boilerplate == isolate->heap()->undefined_value()) {
584 boilerplate = CreateObjectLiteralBoilerplate(isolate,
585 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 should_have_fast_elements,
588 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 if (boilerplate.is_null()) return Failure::Exception();
590 // Update the functions literal and return the boilerplate.
591 literals->set(literals_index, *boilerplate);
592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594}
595
596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000597RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 ASSERT(args.length() == 3);
600 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000601 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
603
604 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 Handle<Object> boilerplate(literals->get(literals_index), isolate);
606 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000607 boilerplate =
608 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 if (boilerplate.is_null()) return Failure::Exception();
610 // Update the functions literal and return the boilerplate.
611 literals->set(literals_index, *boilerplate);
612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 ASSERT(args.length() == 3);
620 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000621 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
623
624 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 Handle<Object> boilerplate(literals->get(literals_index), isolate);
626 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000627 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000634 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000636 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639}
640
641
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
643 ASSERT(args.length() == 2);
644 Object* handler = args[0];
645 Object* prototype = args[1];
646 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000648 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
649}
650
651
lrn@chromium.org34e60782011-09-15 07:25:40 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
653 ASSERT(args.length() == 4);
654 Object* handler = args[0];
655 Object* call_trap = args[1];
656 Object* construct_trap = args[2];
657 Object* prototype = args[3];
658 Object* used_prototype =
659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
660 return isolate->heap()->AllocateJSFunctionProxy(
661 handler, call_trap, construct_trap, used_prototype);
662}
663
664
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
666 ASSERT(args.length() == 1);
667 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000668 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669}
670
671
lrn@chromium.org34e60782011-09-15 07:25:40 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
673 ASSERT(args.length() == 1);
674 Object* obj = args[0];
675 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
676}
677
678
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(JSProxy, proxy, args[0]);
682 return proxy->handler();
683}
684
685
lrn@chromium.org34e60782011-09-15 07:25:40 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
687 ASSERT(args.length() == 1);
688 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
689 return proxy->call_trap();
690}
691
692
693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
694 ASSERT(args.length() == 1);
695 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
696 return proxy->construct_trap();
697}
698
699
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
701 ASSERT(args.length() == 1);
702 CONVERT_CHECKED(JSProxy, proxy, args[0]);
703 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000704 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000705}
706
707
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
709 HandleScope scope(isolate);
710 ASSERT(args.length() == 1);
711 CONVERT_ARG_CHECKED(JSSet, holder, 0);
712 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
713 holder->set_table(*table);
714 return *holder;
715}
716
717
718RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
719 HandleScope scope(isolate);
720 ASSERT(args.length() == 2);
721 CONVERT_ARG_CHECKED(JSSet, holder, 0);
722 Handle<Object> key(args[1]);
723 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
724 table = ObjectHashSetAdd(table, key);
725 holder->set_table(*table);
726 return isolate->heap()->undefined_symbol();
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 return isolate->heap()->ToBoolean(table->Contains(*key));
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetRemove(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 1);
755 CONVERT_ARG_CHECKED(JSMap, holder, 0);
756 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
757 holder->set_table(*table);
758 return *holder;
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSMap, holder, 0);
766 Handle<Object> key(args[1]);
767 return ObjectHashTable::cast(holder->table())->Lookup(*key);
768}
769
770
771RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
772 HandleScope scope(isolate);
773 ASSERT(args.length() == 3);
774 CONVERT_ARG_CHECKED(JSMap, holder, 0);
775 Handle<Object> key(args[1]);
776 Handle<Object> value(args[2]);
777 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
778 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
779 holder->set_table(*new_table);
780 return *value;
781}
782
783
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000784RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 1);
787 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
788 ASSERT(weakmap->map()->inobject_properties() == 0);
789 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
790 weakmap->set_table(*table);
791 weakmap->set_next(Smi::FromInt(0));
792 return *weakmap;
793}
794
795
796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
801 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000802}
803
804
805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 3);
808 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000809 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000811 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000812 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
813 weakmap->set_table(*new_table);
814 return *value;
815}
816
817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000818RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 NoHandleAllocation ha;
820 ASSERT(args.length() == 1);
821 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 return JSObject::cast(obj)->class_name();
824}
825
ager@chromium.org7c537e22008-10-16 08:43:32 +0000826
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
828 NoHandleAllocation ha;
829 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
831 Object* obj = input_obj;
832 // We don't expect access checks to be needed on JSProxy objects.
833 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000834 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000835 if (obj->IsAccessCheckNeeded() &&
836 !isolate->MayNamedAccess(JSObject::cast(obj),
837 isolate->heap()->Proto_symbol(),
838 v8::ACCESS_GET)) {
839 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
840 return isolate->heap()->undefined_value();
841 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000842 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000843 } while (obj->IsJSObject() &&
844 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000845 return obj;
846}
847
848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
853 Object* O = args[0];
854 Object* V = args[1];
855 while (true) {
856 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 if (prototype->IsNull()) return isolate->heap()->false_value();
858 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 V = prototype;
860 }
861}
862
863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000866 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000867 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869}
870
871
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000872// Recursively traverses hidden prototypes if property is not found
873static void GetOwnPropertyImplementation(JSObject* obj,
874 String* name,
875 LookupResult* result) {
876 obj->LocalLookupRealNamedProperty(name, result);
877
878 if (!result->IsProperty()) {
879 Object* proto = obj->GetPrototype();
880 if (proto->IsJSObject() &&
881 JSObject::cast(proto)->map()->is_hidden_prototype())
882 GetOwnPropertyImplementation(JSObject::cast(proto),
883 name, result);
884 }
885}
886
887
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000888static bool CheckAccessException(LookupResult* result,
889 v8::AccessType access_type) {
890 if (result->type() == CALLBACKS) {
891 Object* callback = result->GetCallbackObject();
892 if (callback->IsAccessorInfo()) {
893 AccessorInfo* info = AccessorInfo::cast(callback);
894 bool can_access =
895 (access_type == v8::ACCESS_HAS &&
896 (info->all_can_read() || info->all_can_write())) ||
897 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
898 (access_type == v8::ACCESS_SET && info->all_can_write());
899 return can_access;
900 }
901 }
902
903 return false;
904}
905
906
907static bool CheckAccess(JSObject* obj,
908 String* name,
909 LookupResult* result,
910 v8::AccessType access_type) {
911 ASSERT(result->IsProperty());
912
913 JSObject* holder = result->holder();
914 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 while (true) {
917 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000919 // Access check callback denied the access, but some properties
920 // can have a special permissions which override callbacks descision
921 // (currently see v8::AccessControl).
922 break;
923 }
924
925 if (current == holder) {
926 return true;
927 }
928
929 current = JSObject::cast(current->GetPrototype());
930 }
931
932 // API callbacks can have per callback access exceptions.
933 switch (result->type()) {
934 case CALLBACKS: {
935 if (CheckAccessException(result, access_type)) {
936 return true;
937 }
938 break;
939 }
940 case INTERCEPTOR: {
941 // If the object has an interceptor, try real named properties.
942 // Overwrite the result to fetch the correct property later.
943 holder->LookupRealNamedProperty(name, result);
944 if (result->IsProperty()) {
945 if (CheckAccessException(result, access_type)) {
946 return true;
947 }
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000956 return false;
957}
958
959
960// TODO(1095): we should traverse hidden prototype hierachy as well.
961static bool CheckElementAccess(JSObject* obj,
962 uint32_t index,
963 v8::AccessType access_type) {
964 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000966 return false;
967 }
968
969 return true;
970}
971
972
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000973// Enumerator used as indices into the array returned from GetOwnProperty
974enum PropertyDescriptorIndices {
975 IS_ACCESSOR_INDEX,
976 VALUE_INDEX,
977 GETTER_INDEX,
978 SETTER_INDEX,
979 WRITABLE_INDEX,
980 ENUMERABLE_INDEX,
981 CONFIGURABLE_INDEX,
982 DESCRIPTOR_SIZE
983};
984
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985// Returns an array with the property description:
986// if args[1] is not a property on args[0]
987// returns undefined
988// if args[1] is a data property on args[0]
989// [false, value, Writeable, Enumerable, Configurable]
990// if args[1] is an accessor on args[0]
991// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 Heap* heap = isolate->heap();
995 HandleScope scope(isolate);
996 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
997 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1000 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001002 // This could be an element.
1003 uint32_t index;
1004 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001005 switch (obj->HasLocalElement(index)) {
1006 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001008
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 case JSObject::STRING_CHARACTER_ELEMENT: {
1010 // Special handling of string objects according to ECMAScript 5
1011 // 15.5.5.2. Note that this might be a string object with elements
1012 // other than the actual string value. This is covered by the
1013 // subsequent cases.
1014 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1015 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001016 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 elms->set(WRITABLE_INDEX, heap->false_value());
1021 elms->set(ENUMERABLE_INDEX, heap->false_value());
1022 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 return *desc;
1024 }
1025
1026 case JSObject::INTERCEPTED_ELEMENT:
1027 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001031 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(WRITABLE_INDEX, heap->true_value());
1033 elms->set(ENUMERABLE_INDEX, heap->true_value());
1034 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001035 return *desc;
1036 }
1037
1038 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001039 Handle<JSObject> holder = obj;
1040 if (obj->IsJSGlobalProxy()) {
1041 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 ASSERT(proto->IsJSGlobalObject());
1044 holder = Handle<JSObject>(JSObject::cast(proto));
1045 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001046 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001047 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001048 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001049 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001051 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001052 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001053 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001055 PropertyDetails details = dictionary->DetailsAt(entry);
1056 switch (details.type()) {
1057 case CALLBACKS: {
1058 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 AccessorPair* accessors =
1060 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001062 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001063 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 }
1065 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001066 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 break;
1069 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001070 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001071 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001073 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001074 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001077 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001078 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001079 default:
1080 UNREACHABLE();
1081 break;
1082 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1084 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001085 return *desc;
1086 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001087 }
1088 }
1089
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001090 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001091 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001092
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001093 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001095 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001097 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001099 }
1100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1102 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001103
1104 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001105 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001106
1107 if (is_js_accessor) {
1108 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001111 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001113 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114 }
1115 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001118 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001121
1122 PropertyAttributes attrs;
1123 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001124 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1126 if (!maybe_value->ToObject(&value)) return maybe_value;
1127 }
1128 elms->set(VALUE_INDEX, value);
1129 }
1130
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001131 return *desc;
1132}
1133
1134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001135RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001136 ASSERT(args.length() == 1);
1137 CONVERT_CHECKED(JSObject, obj, args[0]);
1138 return obj->PreventExtensions();
1139}
1140
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001142RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001143 ASSERT(args.length() == 1);
1144 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 if (obj->IsJSGlobalProxy()) {
1146 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001148 ASSERT(proto->IsJSGlobalObject());
1149 obj = JSObject::cast(proto);
1150 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001158 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1159 CONVERT_ARG_CHECKED(String, pattern, 1);
1160 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001161 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1162 if (result.is_null()) return Failure::Exception();
1163 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164}
1165
1166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001167RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001170 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172}
1173
1174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001175RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 ASSERT(args.length() == 1);
1177 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001178 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 ASSERT(args.length() == 2);
1185 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001187 int index = field->value();
1188 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1189 InstanceType type = templ->map()->instance_type();
1190 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1191 type == OBJECT_TEMPLATE_INFO_TYPE);
1192 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001193 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001194 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1195 } else {
1196 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1197 }
1198 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199}
1200
1201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001202RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001203 ASSERT(args.length() == 1);
1204 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001205 Map* old_map = object->map();
1206 bool needs_access_checks = old_map->is_access_check_needed();
1207 if (needs_access_checks) {
1208 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001209 Object* new_map;
1210 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1211 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1212 }
ager@chromium.org32912102009-01-16 10:38:43 +00001213
1214 Map::cast(new_map)->set_is_access_check_needed(false);
1215 object->set_map(Map::cast(new_map));
1216 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001217 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222 ASSERT(args.length() == 1);
1223 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001224 Map* old_map = object->map();
1225 if (!old_map->is_access_check_needed()) {
1226 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 Object* new_map;
1228 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1229 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1230 }
ager@chromium.org32912102009-01-16 10:38:43 +00001231
1232 Map::cast(new_map)->set_is_access_check_needed(true);
1233 object->set_map(Map::cast(new_map));
1234 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001236}
1237
1238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239static Failure* ThrowRedeclarationError(Isolate* isolate,
1240 const char* type,
1241 Handle<String> name) {
1242 HandleScope scope(isolate);
1243 Handle<Object> type_handle =
1244 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 Handle<Object> args[2] = { type_handle, name };
1246 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1248 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249}
1250
1251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001252RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 HandleScope scope(isolate);
1255 Handle<GlobalObject> global = Handle<GlobalObject>(
1256 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
ager@chromium.org3811b432009-10-28 14:53:37 +00001258 Handle<Context> context = args.at<Context>(0);
1259 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001260 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 // Traverse the name/value pairs and set the properties.
1263 int length = pairs->length();
1264 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 // We have to declare a global const property. To capture we only
1270 // assign to it when evaluating the assignment for "const x =
1271 // <expr>" the initial value is the hole.
1272 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 if (value->IsUndefined() || is_const_property) {
1275 // Lookup the property in the global object, and don't set the
1276 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 global->Lookup(*name, &lookup);
1279 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 // We found an existing property. Unless it was an interceptor
1281 // that claims the property is absent, skip this declaration.
1282 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 continue;
1284 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1286 if (attributes != ABSENT) {
1287 continue;
1288 }
1289 // Fall-through and introduce the absent property by using
1290 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 }
1292 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001295 Handle<SharedFunctionInfo> shared =
1296 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1299 context,
1300 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 value = function;
1302 }
1303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001304 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 global->LocalLookup(*name, &lookup);
1306
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001307 // Compute the property attributes. According to ECMA-262, section
1308 // 13, page 71, the property must be read-only and
1309 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1310 // property as read-only, so we don't either.
1311 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 attr |= DONT_DELETE;
1314 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001316 if (is_const_property || (is_native && is_function_declaration)) {
1317 attr |= READ_ONLY;
1318 }
1319
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Safari does not allow the invocation of callback setters for
1321 // function declarations. To mimic this behavior, we do not allow
1322 // the invocation of setters for function values. This makes a
1323 // difference for global functions with the same names as event
1324 // handlers such as "function onload() {}". Firefox does call the
1325 // onload setter in those case and Safari does not. We follow
1326 // Safari for compatibility.
1327 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 // Do not change DONT_DELETE to false from true.
1329 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001330 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001331 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001332 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1333
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001334 RETURN_IF_EMPTY_HANDLE(
1335 isolate,
1336 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1337 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001342 RETURN_IF_EMPTY_HANDLE(
1343 isolate,
1344 JSReceiver::SetProperty(global, name, value,
1345 static_cast<PropertyAttributes>(attr),
1346 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 ASSERT(!isolate->has_pending_exception());
1351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001359 // Declarations are always made in a function or global context. In the
1360 // case of eval code, the context passed is the context of the caller,
1361 // which may be some nested context and not the declaration context.
1362 RUNTIME_ASSERT(args[0]->IsContext());
1363 Handle<Context> context(Context::cast(args[0])->declaration_context());
1364
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001367 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 int index;
1371 PropertyAttributes attributes;
1372 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001373 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001374 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001375 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1380 // Functions are not read-only.
1381 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1382 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
1385
1386 // Initialize it if necessary.
1387 if (*initial_value != NULL) {
1388 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 ASSERT(holder.is_identical_to(context));
1390 if (((attributes & READ_ONLY) == 0) ||
1391 context->get(index)->IsTheHole()) {
1392 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 }
1394 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 // Slow case: The property is in the context extension object of a
1396 // function context or the global object of a global context.
1397 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001400 JSReceiver::SetProperty(object, name, initial_value, mode,
1401 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001410 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001435 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001437 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 }
1440 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001441 RETURN_IF_EMPTY_HANDLE(
1442 isolate,
1443 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001444 }
1445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001453 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001454 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001476 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001480 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001485 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001495 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 } else {
1497 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001498 }
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
1503
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001534 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 RETURN_IF_EMPTY_HANDLE(
1553 isolate,
1554 JSReceiver::SetProperty(global, name, value, attributes,
1555 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 return *value;
1557 }
1558
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // constant. For now, we determine this by checking if the
1561 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 PropertyType type = lookup.type();
1564 if (type == FIELD) {
1565 FixedArray* properties = global->properties();
1566 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 properties->set(index, *value);
1569 }
1570 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1572 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001573 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575 } else {
1576 // Ignore re-initialization of constants that have already been
1577 // assigned a function value.
1578 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1579 }
1580
1581 // Use the set value as the result of the operation.
1582 return *value;
1583}
1584
1585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001586RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 ASSERT(args.length() == 3);
1589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001593 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 RUNTIME_ASSERT(args[1]->IsContext());
1595 Handle<Context> context(Context::cast(args[1])->declaration_context());
1596
1597 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
1599 int index;
1600 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001602 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001603 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001604 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 ASSERT(holder->IsContext());
1608 // Property was found in a context. Perform the assignment if we
1609 // found some non-constant or an uninitialized constant.
1610 Handle<Context> context = Handle<Context>::cast(holder);
1611 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1612 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 }
1614 return *value;
1615 }
1616
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 // The property could not be found, we introduce it as a property of the
1618 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Handle<JSObject> global = Handle<JSObject>(
1621 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 // Strict mode not needed (const disallowed in strict mode).
1623 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001625 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 return *value;
1627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property was present in some function's context extension object,
1630 // as a property on the subject of a with, or as a property of the global
1631 // object.
1632 //
1633 // In most situations, eval-introduced consts should still be present in
1634 // the context extension object. However, because declaration and
1635 // initialization are separate, the property might have been deleted
1636 // before we reach the initialization point.
1637 //
1638 // Example:
1639 //
1640 // function f() { eval("delete x; const x;"); }
1641 //
1642 // In that case, the initialization behaves like a normal assignment.
1643 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 if (*object == context->extension()) {
1646 // This is the property that was introduced by the const declaration.
1647 // Set it if it hasn't been set before. NOTE: We cannot use
1648 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001651 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1653
1654 PropertyType type = lookup.type();
1655 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001656 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001657 int index = lookup.GetFieldIndex();
1658 if (properties->get(index)->IsTheHole()) {
1659 properties->set(index, *value);
1660 }
1661 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1663 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 }
1665 } else {
1666 // We should not reach here. Any real, named property should be
1667 // either a field or a dictionary slot.
1668 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 }
1670 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 // The property was found on some other object. Set it if it is not a
1672 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001673 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001674 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001675 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001677 JSReceiver::SetProperty(object, name, value, attributes,
1678 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 return *value;
1683}
1684
1685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686RUNTIME_FUNCTION(MaybeObject*,
1687 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001691 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001692 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001693 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001694 }
1695 return *object;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001701 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001702 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1703 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001704 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001705 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001706 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001707 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001708 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001709 RUNTIME_ASSERT(index >= 0);
1710 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001712 Handle<Object> result = RegExpImpl::Exec(regexp,
1713 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001716 if (result.is_null()) return Failure::Exception();
1717 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718}
1719
1720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001723 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001724 if (elements_count < 0 ||
1725 elements_count > FixedArray::kMaxLength ||
1726 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 Object* new_object;
1730 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1733 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1736 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1738 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001739 {
1740 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 }
1745 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 array->set_elements(elements);
1748 array->set_length(Smi::FromInt(elements_count));
1749 // Write in-object properties after the length of the array.
1750 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1751 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1752 return array;
1753}
1754
1755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001756RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001757 AssertNoAllocation no_alloc;
1758 ASSERT(args.length() == 5);
1759 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1760 CONVERT_CHECKED(String, source, args[1]);
1761
1762 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001764
1765 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767
1768 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Map* map = regexp->map();
1772 Object* constructor = map->constructor();
1773 if (constructor->IsJSFunction() &&
1774 JSFunction::cast(constructor)->initial_map() == map) {
1775 // If we still have the original map, set in-object properties directly.
1776 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001777 // Both true and false are immovable immortal objects so no need for write
1778 // barrier.
1779 regexp->InObjectPropertyAtPut(
1780 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1781 regexp->InObjectPropertyAtPut(
1782 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1783 regexp->InObjectPropertyAtPut(
1784 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001787 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001788 return regexp;
1789 }
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001797 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001799 source,
1800 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001803 global,
1804 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001805 ASSERT(!result->IsFailure());
1806 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001808 ignoreCase,
1809 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 multiline,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
1815 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001817 Smi::FromInt(0),
1818 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 ASSERT(!result->IsFailure());
1820 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 return regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001832 return Smi::FromInt(0);
1833}
1834
1835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001839 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001849 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 return optimized;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001866
1867 return *holder;
1868}
1869
1870
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001872 ASSERT(args.length() == 1);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001873 CONVERT_CHECKED(JSReceiver, callable, args[0]);
1874
1875 if (!callable->IsJSFunction()) {
1876 HandleScope scope(isolate);
1877 bool threw = false;
1878 Handle<Object> delegate =
1879 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1880 if (threw) return Failure::Exception();
1881 callable = JSFunction::cast(*delegate);
1882 }
1883 JSFunction* function = JSFunction::cast(callable);
1884
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001885 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001886 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001887 return isolate->heap()->undefined_value();
1888 }
1889 // Returns undefined for strict or native functions, or
1890 // the associated global receiver for "normal" functions.
1891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001892 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001893 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001894 return global_context->global()->global_receiver();
1895}
1896
1897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001898RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 ASSERT(args.length() == 4);
1901 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001902 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 Handle<String> pattern = args.at<String>(2);
1904 Handle<String> flags = args.at<String>(3);
1905
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001906 // Get the RegExp function from the context in the literals array.
1907 // This is the RegExp function from the context in which the
1908 // function was created. We do not use the RegExp function from the
1909 // current global context because this might be the RegExp function
1910 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001911 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001912 Handle<JSFunction>(
1913 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 // Compute the regular expression literal.
1915 bool has_pending_exception;
1916 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001917 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1918 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001920 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 return Failure::Exception();
1922 }
1923 literals->set(index, *regexp);
1924 return *regexp;
1925}
1926
1927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, f, args[0]);
1933 return f->shared()->name();
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 2);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 CONVERT_CHECKED(String, name, args[1]);
1943 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001944 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001945}
1946
1947
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
1952 return isolate->heap()->ToBoolean(
1953 f->shared()->name_should_print_as_anonymous());
1954}
1955
1956
1957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960 CONVERT_CHECKED(JSFunction, f, args[0]);
1961 f->shared()->set_name_should_print_as_anonymous(true);
1962 return isolate->heap()->undefined_value();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 Object* obj = f->RemovePrototype();
1972 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001974 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1984 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985
1986 return *GetScriptWrapper(Handle<Script>::cast(script));
1987}
1988
1989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 NoHandleAllocation ha;
1992 ASSERT(args.length() == 1);
1993
1994 CONVERT_CHECKED(JSFunction, f, args[0]);
1995 return f->shared()->GetSourceCode();
1996}
1997
1998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001999RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 NoHandleAllocation ha;
2001 ASSERT(args.length() == 1);
2002
2003 CONVERT_CHECKED(JSFunction, fun, args[0]);
2004 int pos = fun->shared()->start_position();
2005 return Smi::FromInt(pos);
2006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002010 ASSERT(args.length() == 2);
2011
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002012 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002013 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2014
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002015 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2016
2017 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019}
2020
2021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 NoHandleAllocation ha;
2024 ASSERT(args.length() == 2);
2025
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(String, name, args[1]);
2028 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030}
2031
2032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002033RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 NoHandleAllocation ha;
2035 ASSERT(args.length() == 2);
2036
2037 CONVERT_CHECKED(JSFunction, fun, args[0]);
2038 CONVERT_CHECKED(Smi, length, args[1]);
2039 fun->shared()->set_length(length->value());
2040 return length;
2041}
2042
2043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002044RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002045 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002049 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002050 Object* obj;
2051 { MaybeObject* maybe_obj =
2052 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2053 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 return args[0]; // return TOS
2056}
2057
2058
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2060 NoHandleAllocation ha;
2061 RUNTIME_ASSERT(args.length() == 1);
2062 CONVERT_CHECKED(JSFunction, function, args[0]);
2063
2064 MaybeObject* maybe_name =
2065 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2066 String* name;
2067 if (!maybe_name->To(&name)) return maybe_name;
2068
2069 if (function->HasFastProperties()) {
2070 // Construct a new field descriptor with updated attributes.
2071 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2072 int index = instance_desc->Search(name);
2073 ASSERT(index != DescriptorArray::kNotFound);
2074 PropertyDetails details(instance_desc->GetDetails(index));
2075 CallbacksDescriptor new_desc(name,
2076 instance_desc->GetValue(index),
2077 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2078 details.index());
2079 // Construct a new field descriptors array containing the new descriptor.
2080 Object* descriptors_unchecked;
2081 { MaybeObject* maybe_descriptors_unchecked =
2082 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2083 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2084 return maybe_descriptors_unchecked;
2085 }
2086 }
2087 DescriptorArray* new_descriptors =
2088 DescriptorArray::cast(descriptors_unchecked);
2089 // Create a new map featuring the new field descriptors array.
2090 Object* map_unchecked;
2091 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2092 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2093 return maybe_map_unchecked;
2094 }
2095 }
2096 Map* new_map = Map::cast(map_unchecked);
2097 new_map->set_instance_descriptors(new_descriptors);
2098 function->set_map(new_map);
2099 } else { // Dictionary properties.
2100 // Directly manipulate the property details.
2101 int entry = function->property_dictionary()->FindEntry(name);
2102 ASSERT(entry != StringDictionary::kNotFound);
2103 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2104 PropertyDetails new_details(
2105 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2106 details.type(),
2107 details.index());
2108 function->property_dictionary()->DetailsAtPut(entry, new_details);
2109 }
2110 return function;
2111}
2112
2113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002114RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002115 NoHandleAllocation ha;
2116 ASSERT(args.length() == 1);
2117
2118 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002119 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002120}
2121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002124 NoHandleAllocation ha;
2125 ASSERT(args.length() == 1);
2126
2127 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002128 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002129}
2130
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002132RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134 ASSERT(args.length() == 2);
2135
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002136 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 Handle<Object> code = args.at<Object>(1);
2138
2139 Handle<Context> context(target->context());
2140
2141 if (!code->IsNull()) {
2142 RUNTIME_ASSERT(code->IsJSFunction());
2143 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002144 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002146 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 return Failure::Exception();
2148 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002149 // Since we don't store the source for this we should never
2150 // optimize this.
2151 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002152 // Set the code, scope info, formal parameter count,
2153 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002154 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002155 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002156 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002157 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002159 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002160 // Set the source code of the target function to undefined.
2161 // SetCode is only used for built-in constructors like String,
2162 // Array, and Object, and some web code
2163 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002165 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002166 // Clear the optimization hints related to the compiled code as these are no
2167 // longer valid when the code is overwritten.
2168 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002169 context = Handle<Context>(fun->context());
2170
2171 // Make sure we get a fresh copy of the literal vector to avoid
2172 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173 int number_of_literals = fun->NumberOfLiterals();
2174 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002177 // Insert the object, regexp and array functions in the literals
2178 // array prefix. These are the functions that will be used when
2179 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002180 literals->set(JSFunction::kLiteralGlobalContextIndex,
2181 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002183 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002184 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002185
2186 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2187 isolate->logger()->LogExistingFunction(
2188 shared, Handle<Code>(shared->code()));
2189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 }
2191
2192 target->set_context(*context);
2193 return *target;
2194}
2195
2196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002197RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002199 ASSERT(args.length() == 2);
2200 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002201 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002202 RUNTIME_ASSERT(num >= 0);
2203 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002205}
2206
2207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002208MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2209 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002210 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002211 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002212 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002214 }
2215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002221 NoHandleAllocation ha;
2222 ASSERT(args.length() == 2);
2223
2224 CONVERT_CHECKED(String, subject, args[0]);
2225 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002226 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002227
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228 uint32_t i = 0;
2229 if (index->IsSmi()) {
2230 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232 i = value;
2233 } else {
2234 ASSERT(index->IsHeapNumber());
2235 double value = HeapNumber::cast(index)->value();
2236 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002237 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002238
2239 // Flatten the string. If someone wants to get a char at an index
2240 // in a cons string, it is likely that more indices will be
2241 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002242 Object* flat;
2243 { MaybeObject* maybe_flat = subject->TryFlatten();
2244 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2245 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 subject = String::cast(flat);
2247
2248 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002250 }
2251
2252 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002253}
2254
2255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002256RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257 NoHandleAllocation ha;
2258 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002260}
2261
lrn@chromium.org25156de2010-04-06 13:10:27 +00002262
2263class FixedArrayBuilder {
2264 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002265 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2266 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002267 length_(0),
2268 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269 // Require a non-zero initial size. Ensures that doubling the size to
2270 // extend the array will work.
2271 ASSERT(initial_capacity > 0);
2272 }
2273
2274 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2275 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002276 length_(0),
2277 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 // Require a non-zero initial size. Ensures that doubling the size to
2279 // extend the array will work.
2280 ASSERT(backing_store->length() > 0);
2281 }
2282
2283 bool HasCapacity(int elements) {
2284 int length = array_->length();
2285 int required_length = length_ + elements;
2286 return (length >= required_length);
2287 }
2288
2289 void EnsureCapacity(int elements) {
2290 int length = array_->length();
2291 int required_length = length_ + elements;
2292 if (length < required_length) {
2293 int new_length = length;
2294 do {
2295 new_length *= 2;
2296 } while (new_length < required_length);
2297 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002298 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 array_->CopyTo(0, *extended_array, 0, length_);
2300 array_ = extended_array;
2301 }
2302 }
2303
2304 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002305 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 ASSERT(length_ < capacity());
2307 array_->set(length_, value);
2308 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002309 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 }
2311
2312 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002313 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002314 ASSERT(length_ < capacity());
2315 array_->set(length_, value);
2316 length_++;
2317 }
2318
2319 Handle<FixedArray> array() {
2320 return array_;
2321 }
2322
2323 int length() {
2324 return length_;
2325 }
2326
2327 int capacity() {
2328 return array_->length();
2329 }
2330
2331 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002332 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002333 result_array->set_length(Smi::FromInt(length_));
2334 return result_array;
2335 }
2336
2337 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002338 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339 target_array->set_length(Smi::FromInt(length_));
2340 return target_array;
2341 }
2342
2343 private:
2344 Handle<FixedArray> array_;
2345 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002346 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347};
2348
2349
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002350// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351const int kStringBuilderConcatHelperLengthBits = 11;
2352const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353
2354template <typename schar>
2355static inline void StringBuilderConcatHelper(String*,
2356 schar*,
2357 FixedArray*,
2358 int);
2359
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2361 StringBuilderSubstringLength;
2362typedef BitField<int,
2363 kStringBuilderConcatHelperLengthBits,
2364 kStringBuilderConcatHelperPositionBits>
2365 StringBuilderSubstringPosition;
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367
2368class ReplacementStringBuilder {
2369 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002370 ReplacementStringBuilder(Heap* heap,
2371 Handle<String> subject,
2372 int estimated_part_count)
2373 : heap_(heap),
2374 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002375 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002377 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002378 // Require a non-zero initial size. Ensures that doubling the size to
2379 // extend the array will work.
2380 ASSERT(estimated_part_count > 0);
2381 }
2382
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2384 int from,
2385 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 ASSERT(from >= 0);
2387 int length = to - from;
2388 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 if (StringBuilderSubstringLength::is_valid(length) &&
2390 StringBuilderSubstringPosition::is_valid(from)) {
2391 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2392 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002393 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002395 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 builder->Add(Smi::FromInt(-length));
2397 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002399 }
2400
2401
2402 void EnsureCapacity(int elements) {
2403 array_builder_.EnsureCapacity(elements);
2404 }
2405
2406
2407 void AddSubjectSlice(int from, int to) {
2408 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 }
2411
2412
2413 void AddString(Handle<String> string) {
2414 int length = string->length();
2415 ASSERT(length > 0);
2416 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002417 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002418 is_ascii_ = false;
2419 }
2420 IncrementCharacterCount(length);
2421 }
2422
2423
2424 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002426 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429 Handle<String> joined_string;
2430 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002431 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 char* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002436 *array_builder_.array(),
2437 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 } else {
2440 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002441 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002442 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002443 uc16* char_buffer = seq->GetChars();
2444 StringBuilderConcatHelper(*subject_,
2445 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 *array_builder_.array(),
2447 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 }
2450 return joined_string;
2451 }
2452
2453
2454 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002455 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 V8::FatalProcessOutOfMemory("String.replace result too large.");
2457 }
2458 character_count_ += by;
2459 }
2460
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002462 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002464
lrn@chromium.org25156de2010-04-06 13:10:27 +00002465 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002466 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2467 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
2470
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2472 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 }
2474
2475
2476 void AddElement(Object* element) {
2477 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 ASSERT(array_builder_.capacity() > array_builder_.length());
2479 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 }
2481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002482 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002483 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 int character_count_;
2486 bool is_ascii_;
2487};
2488
2489
2490class CompiledReplacement {
2491 public:
2492 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002493 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494
2495 void Compile(Handle<String> replacement,
2496 int capture_count,
2497 int subject_length);
2498
2499 void Apply(ReplacementStringBuilder* builder,
2500 int match_from,
2501 int match_to,
2502 Handle<JSArray> last_match_info);
2503
2504 // Number of distinct parts of the replacement pattern.
2505 int parts() {
2506 return parts_.length();
2507 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002508
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002509 bool simple_hint() {
2510 return simple_hint_;
2511 }
2512
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002513 private:
2514 enum PartType {
2515 SUBJECT_PREFIX = 1,
2516 SUBJECT_SUFFIX,
2517 SUBJECT_CAPTURE,
2518 REPLACEMENT_SUBSTRING,
2519 REPLACEMENT_STRING,
2520
2521 NUMBER_OF_PART_TYPES
2522 };
2523
2524 struct ReplacementPart {
2525 static inline ReplacementPart SubjectMatch() {
2526 return ReplacementPart(SUBJECT_CAPTURE, 0);
2527 }
2528 static inline ReplacementPart SubjectCapture(int capture_index) {
2529 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2530 }
2531 static inline ReplacementPart SubjectPrefix() {
2532 return ReplacementPart(SUBJECT_PREFIX, 0);
2533 }
2534 static inline ReplacementPart SubjectSuffix(int subject_length) {
2535 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2536 }
2537 static inline ReplacementPart ReplacementString() {
2538 return ReplacementPart(REPLACEMENT_STRING, 0);
2539 }
2540 static inline ReplacementPart ReplacementSubString(int from, int to) {
2541 ASSERT(from >= 0);
2542 ASSERT(to > from);
2543 return ReplacementPart(-from, to);
2544 }
2545
2546 // If tag <= 0 then it is the negation of a start index of a substring of
2547 // the replacement pattern, otherwise it's a value from PartType.
2548 ReplacementPart(int tag, int data)
2549 : tag(tag), data(data) {
2550 // Must be non-positive or a PartType value.
2551 ASSERT(tag < NUMBER_OF_PART_TYPES);
2552 }
2553 // Either a value of PartType or a non-positive number that is
2554 // the negation of an index into the replacement string.
2555 int tag;
2556 // The data value's interpretation depends on the value of tag:
2557 // tag == SUBJECT_PREFIX ||
2558 // tag == SUBJECT_SUFFIX: data is unused.
2559 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2560 // tag == REPLACEMENT_SUBSTRING ||
2561 // tag == REPLACEMENT_STRING: data is index into array of substrings
2562 // of the replacement string.
2563 // tag <= 0: Temporary representation of the substring of the replacement
2564 // string ranging over -tag .. data.
2565 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2566 // substring objects.
2567 int data;
2568 };
2569
2570 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002571 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 Vector<Char> characters,
2573 int capture_count,
2574 int subject_length) {
2575 int length = characters.length();
2576 int last = 0;
2577 for (int i = 0; i < length; i++) {
2578 Char c = characters[i];
2579 if (c == '$') {
2580 int next_index = i + 1;
2581 if (next_index == length) { // No next character!
2582 break;
2583 }
2584 Char c2 = characters[next_index];
2585 switch (c2) {
2586 case '$':
2587 if (i > last) {
2588 // There is a substring before. Include the first "$".
2589 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2590 last = next_index + 1; // Continue after the second "$".
2591 } else {
2592 // Let the next substring start with the second "$".
2593 last = next_index;
2594 }
2595 i = next_index;
2596 break;
2597 case '`':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectPrefix());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '\'':
2606 if (i > last) {
2607 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2608 }
2609 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2610 i = next_index;
2611 last = i + 1;
2612 break;
2613 case '&':
2614 if (i > last) {
2615 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2616 }
2617 parts->Add(ReplacementPart::SubjectMatch());
2618 i = next_index;
2619 last = i + 1;
2620 break;
2621 case '0':
2622 case '1':
2623 case '2':
2624 case '3':
2625 case '4':
2626 case '5':
2627 case '6':
2628 case '7':
2629 case '8':
2630 case '9': {
2631 int capture_ref = c2 - '0';
2632 if (capture_ref > capture_count) {
2633 i = next_index;
2634 continue;
2635 }
2636 int second_digit_index = next_index + 1;
2637 if (second_digit_index < length) {
2638 // Peek ahead to see if we have two digits.
2639 Char c3 = characters[second_digit_index];
2640 if ('0' <= c3 && c3 <= '9') { // Double digits.
2641 int double_digit_ref = capture_ref * 10 + c3 - '0';
2642 if (double_digit_ref <= capture_count) {
2643 next_index = second_digit_index;
2644 capture_ref = double_digit_ref;
2645 }
2646 }
2647 }
2648 if (capture_ref > 0) {
2649 if (i > last) {
2650 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2651 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002652 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2654 last = next_index + 1;
2655 }
2656 i = next_index;
2657 break;
2658 }
2659 default:
2660 i = next_index;
2661 break;
2662 }
2663 }
2664 }
2665 if (length > last) {
2666 if (last == 0) {
2667 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669 } else {
2670 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2671 }
2672 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002673 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 }
2675
2676 ZoneList<ReplacementPart> parts_;
2677 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002678 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679};
2680
2681
2682void CompiledReplacement::Compile(Handle<String> replacement,
2683 int capture_count,
2684 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002685 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002687 String::FlatContent content = replacement->GetFlatContent();
2688 ASSERT(content.IsFlat());
2689 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002690 simple_hint_ = ParseReplacementPattern(&parts_,
2691 content.ToAsciiVector(),
2692 capture_count,
2693 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002694 } else {
2695 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002696 simple_hint_ = ParseReplacementPattern(&parts_,
2697 content.ToUC16Vector(),
2698 capture_count,
2699 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002700 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002702 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002703 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 int substring_index = 0;
2705 for (int i = 0, n = parts_.length(); i < n; i++) {
2706 int tag = parts_[i].tag;
2707 if (tag <= 0) { // A replacement string slice.
2708 int from = -tag;
2709 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002710 replacement_substrings_.Add(
2711 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002712 parts_[i].tag = REPLACEMENT_SUBSTRING;
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 } else if (tag == REPLACEMENT_STRING) {
2716 replacement_substrings_.Add(replacement);
2717 parts_[i].data = substring_index;
2718 substring_index++;
2719 }
2720 }
2721}
2722
2723
2724void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2725 int match_from,
2726 int match_to,
2727 Handle<JSArray> last_match_info) {
2728 for (int i = 0, n = parts_.length(); i < n; i++) {
2729 ReplacementPart part = parts_[i];
2730 switch (part.tag) {
2731 case SUBJECT_PREFIX:
2732 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2733 break;
2734 case SUBJECT_SUFFIX: {
2735 int subject_length = part.data;
2736 if (match_to < subject_length) {
2737 builder->AddSubjectSlice(match_to, subject_length);
2738 }
2739 break;
2740 }
2741 case SUBJECT_CAPTURE: {
2742 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002743 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002744 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2745 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2746 if (from >= 0 && to > from) {
2747 builder->AddSubjectSlice(from, to);
2748 }
2749 break;
2750 }
2751 case REPLACEMENT_SUBSTRING:
2752 case REPLACEMENT_STRING:
2753 builder->AddString(replacement_substrings_[part.data]);
2754 break;
2755 default:
2756 UNREACHABLE();
2757 }
2758 }
2759}
2760
2761
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002762void FindAsciiStringIndices(Vector<const char> subject,
2763 char pattern,
2764 ZoneList<int>* indices,
2765 unsigned int limit) {
2766 ASSERT(limit > 0);
2767 // Collect indices of pattern in subject using memchr.
2768 // Stop after finding at most limit values.
2769 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2770 const char* subject_end = subject_start + subject.length();
2771 const char* pos = subject_start;
2772 while (limit > 0) {
2773 pos = reinterpret_cast<const char*>(
2774 memchr(pos, pattern, subject_end - pos));
2775 if (pos == NULL) return;
2776 indices->Add(static_cast<int>(pos - subject_start));
2777 pos++;
2778 limit--;
2779 }
2780}
2781
2782
2783template <typename SubjectChar, typename PatternChar>
2784void FindStringIndices(Isolate* isolate,
2785 Vector<const SubjectChar> subject,
2786 Vector<const PatternChar> pattern,
2787 ZoneList<int>* indices,
2788 unsigned int limit) {
2789 ASSERT(limit > 0);
2790 // Collect indices of pattern in subject.
2791 // Stop after finding at most limit values.
2792 int pattern_length = pattern.length();
2793 int index = 0;
2794 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2795 while (limit > 0) {
2796 index = search.Search(subject, index);
2797 if (index < 0) return;
2798 indices->Add(index);
2799 index += pattern_length;
2800 limit--;
2801 }
2802}
2803
2804
2805void FindStringIndicesDispatch(Isolate* isolate,
2806 String* subject,
2807 String* pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 {
2811 AssertNoAllocation no_gc;
2812 String::FlatContent subject_content = subject->GetFlatContent();
2813 String::FlatContent pattern_content = pattern->GetFlatContent();
2814 ASSERT(subject_content.IsFlat());
2815 ASSERT(pattern_content.IsFlat());
2816 if (subject_content.IsAscii()) {
2817 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2818 if (pattern_content.IsAscii()) {
2819 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2820 if (pattern_vector.length() == 1) {
2821 FindAsciiStringIndices(subject_vector,
2822 pattern_vector[0],
2823 indices,
2824 limit);
2825 } else {
2826 FindStringIndices(isolate,
2827 subject_vector,
2828 pattern_vector,
2829 indices,
2830 limit);
2831 }
2832 } else {
2833 FindStringIndices(isolate,
2834 subject_vector,
2835 pattern_content.ToUC16Vector(),
2836 indices,
2837 limit);
2838 }
2839 } else {
2840 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002841 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002842 FindStringIndices(isolate,
2843 subject_vector,
2844 pattern_content.ToAsciiVector(),
2845 indices,
2846 limit);
2847 } else {
2848 FindStringIndices(isolate,
2849 subject_vector,
2850 pattern_content.ToUC16Vector(),
2851 indices,
2852 limit);
2853 }
2854 }
2855 }
2856}
2857
2858
2859template<typename ResultSeqString>
2860MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2861 Isolate* isolate,
2862 Handle<String> subject,
2863 Handle<JSRegExp> pattern_regexp,
2864 Handle<String> replacement) {
2865 ASSERT(subject->IsFlat());
2866 ASSERT(replacement->IsFlat());
2867
2868 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2869 ZoneList<int> indices(8);
2870 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2871 String* pattern =
2872 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2873 int subject_len = subject->length();
2874 int pattern_len = pattern->length();
2875 int replacement_len = replacement->length();
2876
2877 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2878
2879 int matches = indices.length();
2880 if (matches == 0) return *subject;
2881
2882 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2883 int subject_pos = 0;
2884 int result_pos = 0;
2885
2886 Handle<ResultSeqString> result;
2887 if (ResultSeqString::kHasAsciiEncoding) {
2888 result = Handle<ResultSeqString>::cast(
2889 isolate->factory()->NewRawAsciiString(result_len));
2890 } else {
2891 result = Handle<ResultSeqString>::cast(
2892 isolate->factory()->NewRawTwoByteString(result_len));
2893 }
2894
2895 for (int i = 0; i < matches; i++) {
2896 // Copy non-matched subject content.
2897 if (subject_pos < indices.at(i)) {
2898 String::WriteToFlat(*subject,
2899 result->GetChars() + result_pos,
2900 subject_pos,
2901 indices.at(i));
2902 result_pos += indices.at(i) - subject_pos;
2903 }
2904
2905 // Replace match.
2906 if (replacement_len > 0) {
2907 String::WriteToFlat(*replacement,
2908 result->GetChars() + result_pos,
2909 0,
2910 replacement_len);
2911 result_pos += replacement_len;
2912 }
2913
2914 subject_pos = indices.at(i) + pattern_len;
2915 }
2916 // Add remaining subject content at the end.
2917 if (subject_pos < subject_len) {
2918 String::WriteToFlat(*subject,
2919 result->GetChars() + result_pos,
2920 subject_pos,
2921 subject_len);
2922 }
2923 return *result;
2924}
2925
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002926
lrn@chromium.org303ada72010-10-27 09:33:13 +00002927MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002929 String* subject,
2930 JSRegExp* regexp,
2931 String* replacement,
2932 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933 ASSERT(subject->IsFlat());
2934 ASSERT(replacement->IsFlat());
2935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002936 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002937
2938 int length = subject->length();
2939 Handle<String> subject_handle(subject);
2940 Handle<JSRegExp> regexp_handle(regexp);
2941 Handle<String> replacement_handle(replacement);
2942 Handle<JSArray> last_match_info_handle(last_match_info);
2943 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2944 subject_handle,
2945 0,
2946 last_match_info_handle);
2947 if (match.is_null()) {
2948 return Failure::Exception();
2949 }
2950 if (match->IsNull()) {
2951 return *subject_handle;
2952 }
2953
2954 int capture_count = regexp_handle->CaptureCount();
2955
2956 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002957 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958 CompiledReplacement compiled_replacement;
2959 compiled_replacement.Compile(replacement_handle,
2960 capture_count,
2961 length);
2962
2963 bool is_global = regexp_handle->GetFlags().is_global();
2964
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002965 // Shortcut for simple non-regexp global replacements
2966 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002967 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002968 compiled_replacement.simple_hint()) {
2969 if (subject_handle->HasOnlyAsciiChars() &&
2970 replacement_handle->HasOnlyAsciiChars()) {
2971 return StringReplaceStringWithString<SeqAsciiString>(
2972 isolate, subject_handle, regexp_handle, replacement_handle);
2973 } else {
2974 return StringReplaceStringWithString<SeqTwoByteString>(
2975 isolate, subject_handle, regexp_handle, replacement_handle);
2976 }
2977 }
2978
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 // Guessing the number of parts that the final result string is built
2980 // from. Global regexps can match any number of times, so we guess
2981 // conservatively.
2982 int expected_parts =
2983 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002984 ReplacementStringBuilder builder(isolate->heap(),
2985 subject_handle,
2986 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987
2988 // Index of end of last match.
2989 int prev = 0;
2990
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002991 // Number of parts added by compiled replacement plus preceeding
2992 // string and possibly suffix after last match. It is possible for
2993 // all components to use two elements when encoded as two smis.
2994 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002995 bool matched = true;
2996 do {
2997 ASSERT(last_match_info_handle->HasFastElements());
2998 // Increase the capacity of the builder before entering local handle-scope,
2999 // so its internal buffer can safely allocate a new handle if it grows.
3000 builder.EnsureCapacity(parts_added_per_loop);
3001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003002 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003003 int start, end;
3004 {
3005 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003006 FixedArray* match_info_array =
3007 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 ASSERT_EQ(capture_count * 2 + 2,
3010 RegExpImpl::GetLastCaptureCount(match_info_array));
3011 start = RegExpImpl::GetCapture(match_info_array, 0);
3012 end = RegExpImpl::GetCapture(match_info_array, 1);
3013 }
3014
3015 if (prev < start) {
3016 builder.AddSubjectSlice(prev, start);
3017 }
3018 compiled_replacement.Apply(&builder,
3019 start,
3020 end,
3021 last_match_info_handle);
3022 prev = end;
3023
3024 // Only continue checking for global regexps.
3025 if (!is_global) break;
3026
3027 // Continue from where the match ended, unless it was an empty match.
3028 int next = end;
3029 if (start == end) {
3030 next = end + 1;
3031 if (next > length) break;
3032 }
3033
3034 match = RegExpImpl::Exec(regexp_handle,
3035 subject_handle,
3036 next,
3037 last_match_info_handle);
3038 if (match.is_null()) {
3039 return Failure::Exception();
3040 }
3041 matched = !match->IsNull();
3042 } while (matched);
3043
3044 if (prev < length) {
3045 builder.AddSubjectSlice(prev, length);
3046 }
3047
3048 return *(builder.ToString());
3049}
3050
3051
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003052template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003053MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003055 String* subject,
3056 JSRegExp* regexp,
3057 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003058 ASSERT(subject->IsFlat());
3059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003060 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003061
3062 Handle<String> subject_handle(subject);
3063 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003064
3065 // Shortcut for simple non-regexp global replacements
3066 if (regexp_handle->GetFlags().is_global() &&
3067 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3068 Handle<String> empty_string_handle(HEAP->empty_string());
3069 if (subject_handle->HasOnlyAsciiChars()) {
3070 return StringReplaceStringWithString<SeqAsciiString>(
3071 isolate, subject_handle, regexp_handle, empty_string_handle);
3072 } else {
3073 return StringReplaceStringWithString<SeqTwoByteString>(
3074 isolate, subject_handle, regexp_handle, empty_string_handle);
3075 }
3076 }
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 Handle<JSArray> last_match_info_handle(last_match_info);
3079 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3080 subject_handle,
3081 0,
3082 last_match_info_handle);
3083 if (match.is_null()) return Failure::Exception();
3084 if (match->IsNull()) return *subject_handle;
3085
3086 ASSERT(last_match_info_handle->HasFastElements());
3087
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 int start, end;
3089 {
3090 AssertNoAllocation match_info_array_is_not_in_a_handle;
3091 FixedArray* match_info_array =
3092 FixedArray::cast(last_match_info_handle->elements());
3093
3094 start = RegExpImpl::GetCapture(match_info_array, 0);
3095 end = RegExpImpl::GetCapture(match_info_array, 1);
3096 }
3097
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003098 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 int new_length = length - (end - start);
3100 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102 }
3103 Handle<ResultSeqString> answer;
3104 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003105 answer = Handle<ResultSeqString>::cast(
3106 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003107 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 answer = Handle<ResultSeqString>::cast(
3109 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003110 }
3111
3112 // If the regexp isn't global, only match once.
3113 if (!regexp_handle->GetFlags().is_global()) {
3114 if (start > 0) {
3115 String::WriteToFlat(*subject_handle,
3116 answer->GetChars(),
3117 0,
3118 start);
3119 }
3120 if (end < length) {
3121 String::WriteToFlat(*subject_handle,
3122 answer->GetChars() + start,
3123 end,
3124 length);
3125 }
3126 return *answer;
3127 }
3128
3129 int prev = 0; // Index of end of last match.
3130 int next = 0; // Start of next search (prev unless last match was empty).
3131 int position = 0;
3132
3133 do {
3134 if (prev < start) {
3135 // Add substring subject[prev;start] to answer string.
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars() + position,
3138 prev,
3139 start);
3140 position += start - prev;
3141 }
3142 prev = end;
3143 next = end;
3144 // Continue from where the match ended, unless it was an empty match.
3145 if (start == end) {
3146 next++;
3147 if (next > length) break;
3148 }
3149 match = RegExpImpl::Exec(regexp_handle,
3150 subject_handle,
3151 next,
3152 last_match_info_handle);
3153 if (match.is_null()) return Failure::Exception();
3154 if (match->IsNull()) break;
3155
3156 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003158 {
3159 AssertNoAllocation match_info_array_is_not_in_a_handle;
3160 FixedArray* match_info_array =
3161 FixedArray::cast(last_match_info_handle->elements());
3162 start = RegExpImpl::GetCapture(match_info_array, 0);
3163 end = RegExpImpl::GetCapture(match_info_array, 1);
3164 }
3165 } while (true);
3166
3167 if (prev < length) {
3168 // Add substring subject[prev;length] to answer string.
3169 String::WriteToFlat(*subject_handle,
3170 answer->GetChars() + position,
3171 prev,
3172 length);
3173 position += length - prev;
3174 }
3175
3176 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003177 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003178 }
3179
3180 // Shorten string and fill
3181 int string_size = ResultSeqString::SizeFor(position);
3182 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3183 int delta = allocated_string_size - string_size;
3184
3185 answer->set_length(position);
3186 if (delta == 0) return *answer;
3187
3188 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003190 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003191 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003192 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003193
3194 return *answer;
3195}
3196
3197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003198RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003199 ASSERT(args.length() == 4);
3200
3201 CONVERT_CHECKED(String, subject, args[0]);
3202 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003203 Object* flat_subject;
3204 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3205 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3206 return maybe_flat_subject;
3207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003208 }
3209 subject = String::cast(flat_subject);
3210 }
3211
3212 CONVERT_CHECKED(String, replacement, args[2]);
3213 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003214 Object* flat_replacement;
3215 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3216 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3217 return maybe_flat_replacement;
3218 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003219 }
3220 replacement = String::cast(flat_replacement);
3221 }
3222
3223 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3224 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3225
3226 ASSERT(last_match_info->HasFastElements());
3227
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 if (replacement->length() == 0) {
3229 if (subject->HasOnlyAsciiChars()) {
3230 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003231 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003232 } else {
3233 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003235 }
3236 }
3237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003238 return StringReplaceRegExpWithString(isolate,
3239 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 regexp,
3241 replacement,
3242 last_match_info);
3243}
3244
3245
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003246Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3247 Handle<String> subject,
3248 Handle<String> search,
3249 Handle<String> replace,
3250 bool* found,
3251 int recursion_limit) {
3252 if (recursion_limit == 0) return Handle<String>::null();
3253 if (subject->IsConsString()) {
3254 ConsString* cons = ConsString::cast(*subject);
3255 Handle<String> first = Handle<String>(cons->first());
3256 Handle<String> second = Handle<String>(cons->second());
3257 Handle<String> new_first =
3258 StringReplaceOneCharWithString(isolate,
3259 first,
3260 search,
3261 replace,
3262 found,
3263 recursion_limit - 1);
3264 if (*found) return isolate->factory()->NewConsString(new_first, second);
3265 if (new_first.is_null()) return new_first;
3266
3267 Handle<String> new_second =
3268 StringReplaceOneCharWithString(isolate,
3269 second,
3270 search,
3271 replace,
3272 found,
3273 recursion_limit - 1);
3274 if (*found) return isolate->factory()->NewConsString(first, new_second);
3275 if (new_second.is_null()) return new_second;
3276
3277 return subject;
3278 } else {
3279 int index = StringMatch(isolate, subject, search, 0);
3280 if (index == -1) return subject;
3281 *found = true;
3282 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3283 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3284 Handle<String> second =
3285 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3286 return isolate->factory()->NewConsString(cons1, second);
3287 }
3288}
3289
3290
3291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3292 ASSERT(args.length() == 3);
3293 HandleScope scope(isolate);
3294 CONVERT_ARG_CHECKED(String, subject, 0);
3295 CONVERT_ARG_CHECKED(String, search, 1);
3296 CONVERT_ARG_CHECKED(String, replace, 2);
3297
3298 // If the cons string tree is too deep, we simply abort the recursion and
3299 // retry with a flattened subject string.
3300 const int kRecursionLimit = 0x1000;
3301 bool found = false;
3302 Handle<String> result =
3303 Runtime::StringReplaceOneCharWithString(isolate,
3304 subject,
3305 search,
3306 replace,
3307 &found,
3308 kRecursionLimit);
3309 if (!result.is_null()) return *result;
3310 return *Runtime::StringReplaceOneCharWithString(isolate,
3311 FlattenGetString(subject),
3312 search,
3313 replace,
3314 &found,
3315 kRecursionLimit);
3316}
3317
3318
ager@chromium.org7c537e22008-10-16 08:43:32 +00003319// Perform string match of pattern on subject, starting at start index.
3320// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003321// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322int Runtime::StringMatch(Isolate* isolate,
3323 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003324 Handle<String> pat,
3325 int start_index) {
3326 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003327 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003328
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003329 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003330 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003332 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003333 if (start_index + pattern_length > subject_length) return -1;
3334
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003335 if (!sub->IsFlat()) FlattenString(sub);
3336 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003337
ager@chromium.org7c537e22008-10-16 08:43:32 +00003338 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003339 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003340 String::FlatContent seq_sub = sub->GetFlatContent();
3341 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003342
ager@chromium.org7c537e22008-10-16 08:43:32 +00003343 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003344 if (seq_pat.IsAscii()) {
3345 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3346 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003348 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 pat_vector,
3350 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003351 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003353 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 pat_vector,
3355 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003356 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003357 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3358 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003359 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003360 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 pat_vector,
3362 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003364 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003366 pat_vector,
3367 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003368}
3369
3370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003371RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003373 ASSERT(args.length() == 3);
3374
ager@chromium.org7c537e22008-10-16 08:43:32 +00003375 CONVERT_ARG_CHECKED(String, sub, 0);
3376 CONVERT_ARG_CHECKED(String, pat, 1);
3377
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003378 Object* index = args[2];
3379 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003380 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003381
ager@chromium.org870a0b62008-11-04 11:43:05 +00003382 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003383 int position =
3384 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003385 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003386}
3387
3388
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003389template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003390static int StringMatchBackwards(Vector<const schar> subject,
3391 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003393 int pattern_length = pattern.length();
3394 ASSERT(pattern_length >= 1);
3395 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396
3397 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003398 for (int i = 0; i < pattern_length; i++) {
3399 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003400 if (c > String::kMaxAsciiCharCode) {
3401 return -1;
3402 }
3403 }
3404 }
3405
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003407 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003408 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003410 while (j < pattern_length) {
3411 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003412 break;
3413 }
3414 j++;
3415 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003416 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417 return i;
3418 }
3419 }
3420 return -1;
3421}
3422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003423RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003424 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 ASSERT(args.length() == 3);
3426
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003427 CONVERT_ARG_CHECKED(String, sub, 0);
3428 CONVERT_ARG_CHECKED(String, pat, 1);
3429
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003432 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003434 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003435 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 if (start_index + pat_length > sub_length) {
3438 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003440
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 if (pat_length == 0) {
3442 return Smi::FromInt(start_index);
3443 }
3444
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003445 if (!sub->IsFlat()) FlattenString(sub);
3446 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003448 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003449 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3450
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003451 String::FlatContent sub_content = sub->GetFlatContent();
3452 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003453
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003454 if (pat_content.IsAscii()) {
3455 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3456 if (sub_content.IsAscii()) {
3457 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 pat_vector,
3459 start_index);
3460 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003461 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 pat_vector,
3463 start_index);
3464 }
3465 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003466 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3467 if (sub_content.IsAscii()) {
3468 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003469 pat_vector,
3470 start_index);
3471 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003473 pat_vector,
3474 start_index);
3475 }
3476 }
3477
3478 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479}
3480
3481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003482RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 NoHandleAllocation ha;
3484 ASSERT(args.length() == 2);
3485
3486 CONVERT_CHECKED(String, str1, args[0]);
3487 CONVERT_CHECKED(String, str2, args[1]);
3488
3489 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003490 int str1_length = str1->length();
3491 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492
3493 // Decide trivial cases without flattening.
3494 if (str1_length == 0) {
3495 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3496 return Smi::FromInt(-str2_length);
3497 } else {
3498 if (str2_length == 0) return Smi::FromInt(str1_length);
3499 }
3500
3501 int end = str1_length < str2_length ? str1_length : str2_length;
3502
3503 // No need to flatten if we are going to find the answer on the first
3504 // character. At this point we know there is at least one character
3505 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003506 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003507 if (d != 0) return Smi::FromInt(d);
3508
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003509 str1->TryFlatten();
3510 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 StringInputBuffer& buf1 =
3513 *isolate->runtime_state()->string_locale_compare_buf1();
3514 StringInputBuffer& buf2 =
3515 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516
3517 buf1.Reset(str1);
3518 buf2.Reset(str2);
3519
3520 for (int i = 0; i < end; i++) {
3521 uint16_t char1 = buf1.GetNext();
3522 uint16_t char2 = buf2.GetNext();
3523 if (char1 != char2) return Smi::FromInt(char1 - char2);
3524 }
3525
3526 return Smi::FromInt(str1_length - str2_length);
3527}
3528
3529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003530RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 NoHandleAllocation ha;
3532 ASSERT(args.length() == 3);
3533
3534 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003535 int start, end;
3536 // We have a fast integer-only case here to avoid a conversion to double in
3537 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003538 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3539 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3540 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3541 start = from_number;
3542 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003543 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003544 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3545 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003546 start = FastD2I(from_number);
3547 end = FastD2I(to_number);
3548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 RUNTIME_ASSERT(end >= start);
3550 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003551 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003553 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554}
3555
3556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003557RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003558 ASSERT_EQ(3, args.length());
3559
3560 CONVERT_ARG_CHECKED(String, subject, 0);
3561 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3562 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3563 HandleScope handles;
3564
3565 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3566
3567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003572 }
3573 int length = subject->length();
3574
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003575 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003576 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003577 int start;
3578 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003580 {
3581 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003582 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003583 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3584 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3585 }
3586 offsets.Add(start);
3587 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003588 if (start == end) if (++end > length) break;
3589 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003590 if (match.is_null()) {
3591 return Failure::Exception();
3592 }
3593 } while (!match->IsNull());
3594 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003596 Handle<String> substring = isolate->factory()->
3597 NewSubString(subject, offsets.at(0), offsets.at(1));
3598 elements->set(0, *substring);
3599 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 int from = offsets.at(i * 2);
3601 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003602 Handle<String> substring = isolate->factory()->
3603 NewProperSubString(subject, from, to);
3604 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003605 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003607 result->set_length(Smi::FromInt(matches));
3608 return *result;
3609}
3610
3611
lrn@chromium.org25156de2010-04-06 13:10:27 +00003612// Two smis before and after the match, for very long strings.
3613const int kMaxBuilderEntriesPerRegExpMatch = 5;
3614
3615
3616static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3617 Handle<JSArray> last_match_info,
3618 int match_start,
3619 int match_end) {
3620 // Fill last_match_info with a single capture.
3621 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3622 AssertNoAllocation no_gc;
3623 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3624 RegExpImpl::SetLastCaptureCount(elements, 2);
3625 RegExpImpl::SetLastInput(elements, *subject);
3626 RegExpImpl::SetLastSubject(elements, *subject);
3627 RegExpImpl::SetCapture(elements, 0, match_start);
3628 RegExpImpl::SetCapture(elements, 1, match_end);
3629}
3630
3631
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003632template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633static bool SearchStringMultiple(Isolate* isolate,
3634 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003635 Vector<const PatternChar> pattern,
3636 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003637 FixedArrayBuilder* builder,
3638 int* match_pos) {
3639 int pos = *match_pos;
3640 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003641 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644 while (pos <= max_search_start) {
3645 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3646 *match_pos = pos;
3647 return false;
3648 }
3649 // Position of end of previous match.
3650 int match_end = pos + pattern_length;
3651 int new_pos = search.Search(subject, match_end);
3652 if (new_pos >= 0) {
3653 // A match.
3654 if (new_pos > match_end) {
3655 ReplacementStringBuilder::AddSubjectSlice(builder,
3656 match_end,
3657 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003659 pos = new_pos;
3660 builder->Add(pattern_string);
3661 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003663 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665
lrn@chromium.org25156de2010-04-06 13:10:27 +00003666 if (pos < max_search_start) {
3667 ReplacementStringBuilder::AddSubjectSlice(builder,
3668 pos + pattern_length,
3669 subject_length);
3670 }
3671 *match_pos = pos;
3672 return true;
3673}
3674
3675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003676static bool SearchStringMultiple(Isolate* isolate,
3677 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 Handle<String> pattern,
3679 Handle<JSArray> last_match_info,
3680 FixedArrayBuilder* builder) {
3681 ASSERT(subject->IsFlat());
3682 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683
3684 // Treating as if a previous match was before first character.
3685 int match_pos = -pattern->length();
3686
3687 for (;;) { // Break when search complete.
3688 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3689 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003690 String::FlatContent subject_content = subject->GetFlatContent();
3691 String::FlatContent pattern_content = pattern->GetFlatContent();
3692 if (subject_content.IsAscii()) {
3693 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3694 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 if (SearchStringMultiple(isolate,
3696 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003697 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003698 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 builder,
3700 &match_pos)) break;
3701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702 if (SearchStringMultiple(isolate,
3703 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003704 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003705 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 builder,
3707 &match_pos)) break;
3708 }
3709 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003710 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3711 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 if (SearchStringMultiple(isolate,
3713 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003714 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003715 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003716 builder,
3717 &match_pos)) break;
3718 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003719 if (SearchStringMultiple(isolate,
3720 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003721 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003722 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003723 builder,
3724 &match_pos)) break;
3725 }
3726 }
3727 }
3728
3729 if (match_pos >= 0) {
3730 SetLastMatchInfoNoCaptures(subject,
3731 last_match_info,
3732 match_pos,
3733 match_pos + pattern->length());
3734 return true;
3735 }
3736 return false; // No matches at all.
3737}
3738
3739
3740static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003742 Handle<String> subject,
3743 Handle<JSRegExp> regexp,
3744 Handle<JSArray> last_match_array,
3745 FixedArrayBuilder* builder) {
3746 ASSERT(subject->IsFlat());
3747 int match_start = -1;
3748 int match_end = 0;
3749 int pos = 0;
3750 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3751 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3752
3753 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003754 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003755 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003756 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003757
3758 for (;;) { // Break on failure, return on exception.
3759 RegExpImpl::IrregexpResult result =
3760 RegExpImpl::IrregexpExecOnce(regexp,
3761 subject,
3762 pos,
3763 register_vector);
3764 if (result == RegExpImpl::RE_SUCCESS) {
3765 match_start = register_vector[0];
3766 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3767 if (match_end < match_start) {
3768 ReplacementStringBuilder::AddSubjectSlice(builder,
3769 match_end,
3770 match_start);
3771 }
3772 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003774 if (!first) {
3775 builder->Add(*isolate->factory()->NewProperSubString(subject,
3776 match_start,
3777 match_end));
3778 } else {
3779 builder->Add(*isolate->factory()->NewSubString(subject,
3780 match_start,
3781 match_end));
3782 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003783 if (match_start != match_end) {
3784 pos = match_end;
3785 } else {
3786 pos = match_end + 1;
3787 if (pos > subject_length) break;
3788 }
3789 } else if (result == RegExpImpl::RE_FAILURE) {
3790 break;
3791 } else {
3792 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3793 return result;
3794 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796 }
3797
3798 if (match_start >= 0) {
3799 if (match_end < subject_length) {
3800 ReplacementStringBuilder::AddSubjectSlice(builder,
3801 match_end,
3802 subject_length);
3803 }
3804 SetLastMatchInfoNoCaptures(subject,
3805 last_match_array,
3806 match_start,
3807 match_end);
3808 return RegExpImpl::RE_SUCCESS;
3809 } else {
3810 return RegExpImpl::RE_FAILURE; // No matches at all.
3811 }
3812}
3813
3814
3815static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003816 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 Handle<String> subject,
3818 Handle<JSRegExp> regexp,
3819 Handle<JSArray> last_match_array,
3820 FixedArrayBuilder* builder) {
3821
3822 ASSERT(subject->IsFlat());
3823 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3824 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3825
3826 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003827 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003828
3829 RegExpImpl::IrregexpResult result =
3830 RegExpImpl::IrregexpExecOnce(regexp,
3831 subject,
3832 0,
3833 register_vector);
3834
3835 int capture_count = regexp->CaptureCount();
3836 int subject_length = subject->length();
3837
3838 // Position to search from.
3839 int pos = 0;
3840 // End of previous match. Differs from pos if match was empty.
3841 int match_end = 0;
3842 if (result == RegExpImpl::RE_SUCCESS) {
3843 // Need to keep a copy of the previous match for creating last_match_info
3844 // at the end, so we have two vectors that we swap between.
3845 OffsetsVector registers2(required_registers);
3846 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003847 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003848 do {
3849 int match_start = register_vector[0];
3850 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3851 if (match_end < match_start) {
3852 ReplacementStringBuilder::AddSubjectSlice(builder,
3853 match_end,
3854 match_start);
3855 }
3856 match_end = register_vector[1];
3857
3858 {
3859 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003860 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003861 // Arguments array to replace function is match, captures, index and
3862 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003863 Handle<FixedArray> elements =
3864 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003865 Handle<String> match;
3866 if (!first) {
3867 match = isolate->factory()->NewProperSubString(subject,
3868 match_start,
3869 match_end);
3870 } else {
3871 match = isolate->factory()->NewSubString(subject,
3872 match_start,
3873 match_end);
3874 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003875 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 for (int i = 1; i <= capture_count; i++) {
3877 int start = register_vector[i * 2];
3878 if (start >= 0) {
3879 int end = register_vector[i * 2 + 1];
3880 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003881 Handle<String> substring;
3882 if (!first) {
3883 substring = isolate->factory()->NewProperSubString(subject,
3884 start,
3885 end);
3886 } else {
3887 substring = isolate->factory()->NewSubString(subject, start, end);
3888 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889 elements->set(i, *substring);
3890 } else {
3891 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003893 }
3894 }
3895 elements->set(capture_count + 1, Smi::FromInt(match_start));
3896 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003898 }
3899 // Swap register vectors, so the last successful match is in
3900 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003901 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 prev_register_vector = register_vector;
3903 register_vector = tmp;
3904
3905 if (match_end > match_start) {
3906 pos = match_end;
3907 } else {
3908 pos = match_end + 1;
3909 if (pos > subject_length) {
3910 break;
3911 }
3912 }
3913
3914 result = RegExpImpl::IrregexpExecOnce(regexp,
3915 subject,
3916 pos,
3917 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003918 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 } while (result == RegExpImpl::RE_SUCCESS);
3920
3921 if (result != RegExpImpl::RE_EXCEPTION) {
3922 // Finished matching, with at least one match.
3923 if (match_end < subject_length) {
3924 ReplacementStringBuilder::AddSubjectSlice(builder,
3925 match_end,
3926 subject_length);
3927 }
3928
3929 int last_match_capture_count = (capture_count + 1) * 2;
3930 int last_match_array_size =
3931 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3932 last_match_array->EnsureSize(last_match_array_size);
3933 AssertNoAllocation no_gc;
3934 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3935 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3936 RegExpImpl::SetLastSubject(elements, *subject);
3937 RegExpImpl::SetLastInput(elements, *subject);
3938 for (int i = 0; i < last_match_capture_count; i++) {
3939 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3940 }
3941 return RegExpImpl::RE_SUCCESS;
3942 }
3943 }
3944 // No matches at all, return failure or exception result directly.
3945 return result;
3946}
3947
3948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003949RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003950 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003952
3953 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003954 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003955 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3956 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3957 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3958
3959 ASSERT(last_match_info->HasFastElements());
3960 ASSERT(regexp->GetFlags().is_global());
3961 Handle<FixedArray> result_elements;
3962 if (result_array->HasFastElements()) {
3963 result_elements =
3964 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003965 }
3966 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003968 }
3969 FixedArrayBuilder builder(result_elements);
3970
3971 if (regexp->TypeTag() == JSRegExp::ATOM) {
3972 Handle<String> pattern(
3973 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003974 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 if (SearchStringMultiple(isolate, subject, pattern,
3976 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003977 return *builder.ToJSArray(result_array);
3978 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 }
3981
3982 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3983
3984 RegExpImpl::IrregexpResult result;
3985 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003986 result = SearchRegExpNoCaptureMultiple(isolate,
3987 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988 regexp,
3989 last_match_info,
3990 &builder);
3991 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 result = SearchRegExpMultiple(isolate,
3993 subject,
3994 regexp,
3995 last_match_info,
3996 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003997 }
3998 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004000 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4001 return Failure::Exception();
4002}
4003
4004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004005RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 NoHandleAllocation ha;
4007 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004008 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004009 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004011 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004012 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004013 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004014 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004015 // Character array used for conversion.
4016 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return isolate->heap()->
4018 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004019 }
4020 }
4021
4022 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004025 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 }
4027 if (isinf(value)) {
4028 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004029 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004031 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004034 MaybeObject* result =
4035 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 DeleteArray(str);
4037 return result;
4038}
4039
4040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 NoHandleAllocation ha;
4043 ASSERT(args.length() == 2);
4044
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004047 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 }
4049 if (isinf(value)) {
4050 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004051 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 int f = FastD2I(f_number);
4057 RUNTIME_ASSERT(f >= 0);
4058 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004059 MaybeObject* res =
4060 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004062 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063}
4064
4065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004066RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 NoHandleAllocation ha;
4068 ASSERT(args.length() == 2);
4069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004070 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
4074 if (isinf(value)) {
4075 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004076 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004080 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 int f = FastD2I(f_number);
4082 RUNTIME_ASSERT(f >= -1 && f <= 20);
4083 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 MaybeObject* res =
4085 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004087 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088}
4089
4090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004091RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 NoHandleAllocation ha;
4093 ASSERT(args.length() == 2);
4094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004095 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
4099 if (isinf(value)) {
4100 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004103 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004105 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 int f = FastD2I(f_number);
4107 RUNTIME_ASSERT(f >= 1 && f <= 21);
4108 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004109 MaybeObject* res =
4110 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004112 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113}
4114
4115
4116// Returns a single character string where first character equals
4117// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004118static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004119 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004120 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004121 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004122 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004124 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125}
4126
4127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4129 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004130 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 // Handle [] indexing on Strings
4132 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004133 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4134 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 }
4136
4137 // Handle [] indexing on String objects
4138 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4140 Handle<Object> result =
4141 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4142 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 }
4144
4145 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004146 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147 }
4148
4149 return object->GetElement(index);
4150}
4151
4152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004153MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4154 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004161 isolate->factory()->NewTypeError("non_object_property_load",
4162 HandleVector(args, 2));
4163 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 // Check if the given key is an array index.
4167 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004168 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 }
4171
4172 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004175 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 bool has_pending_exception = false;
4178 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004181 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 }
4183
ager@chromium.org32912102009-01-16 10:38:43 +00004184 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 // the element if so.
4186 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004189 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 }
4191}
4192
4193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004194RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 NoHandleAllocation ha;
4196 ASSERT(args.length() == 2);
4197
4198 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004199 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202}
4203
4204
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004205MaybeObject* TransitionElements(Handle<Object> object,
4206 ElementsKind to_kind,
4207 Isolate* isolate) {
4208 HandleScope scope(isolate);
4209 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4210 ElementsKind from_kind =
4211 Handle<JSObject>::cast(object)->map()->elements_kind();
4212 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004213 Handle<Object> result = JSObject::TransitionElementsKind(
4214 Handle<JSObject>::cast(object), to_kind);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004215 if (result.is_null()) return isolate->ThrowIllegalOperation();
4216 return *result;
4217 }
4218 return isolate->ThrowIllegalOperation();
4219}
4220
4221
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004222// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004223RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004224 NoHandleAllocation ha;
4225 ASSERT(args.length() == 2);
4226
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004227 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004228 // itself.
4229 //
4230 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004231 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // global proxy object never has properties. This is the case
4233 // because the global proxy object forwards everything to its hidden
4234 // prototype including local lookups.
4235 //
4236 // Additionally, we need to make sure that we do not cache results
4237 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004238 if (args[0]->IsJSObject()) {
4239 if (!args[0]->IsJSGlobalProxy() &&
4240 !args[0]->IsAccessCheckNeeded() &&
4241 args[1]->IsString()) {
4242 JSObject* receiver = JSObject::cast(args[0]);
4243 String* key = String::cast(args[1]);
4244 if (receiver->HasFastProperties()) {
4245 // Attempt to use lookup cache.
4246 Map* receiver_map = receiver->map();
4247 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4248 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4249 if (offset != -1) {
4250 Object* value = receiver->FastPropertyAt(offset);
4251 return value->IsTheHole()
4252 ? isolate->heap()->undefined_value()
4253 : value;
4254 }
4255 // Lookup cache miss. Perform lookup and update the cache if
4256 // appropriate.
4257 LookupResult result(isolate);
4258 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004259 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004260 int offset = result.GetFieldIndex();
4261 keyed_lookup_cache->Update(receiver_map, key, offset);
4262 return receiver->FastPropertyAt(offset);
4263 }
4264 } else {
4265 // Attempt dictionary lookup.
4266 StringDictionary* dictionary = receiver->property_dictionary();
4267 int entry = dictionary->FindEntry(key);
4268 if ((entry != StringDictionary::kNotFound) &&
4269 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4270 Object* value = dictionary->ValueAt(entry);
4271 if (!receiver->IsGlobalObject()) return value;
4272 value = JSGlobalPropertyCell::cast(value)->value();
4273 if (!value->IsTheHole()) return value;
4274 // If value is the hole do the general lookup.
4275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004276 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004277 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4278 // JSObject without a string key. If the key is a Smi, check for a
4279 // definite out-of-bounds access to elements, which is a strong indicator
4280 // that subsequent accesses will also call the runtime. Proactively
4281 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4282 // doubles for those future calls in the case that the elements would
4283 // become FAST_DOUBLE_ELEMENTS.
4284 Handle<JSObject> js_object(args.at<JSObject>(0));
4285 ElementsKind elements_kind = js_object->GetElementsKind();
4286 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4287 elements_kind == FAST_DOUBLE_ELEMENTS) {
4288 FixedArrayBase* elements = js_object->elements();
4289 if (args.at<Smi>(1)->value() >= elements->length()) {
4290 MaybeObject* maybe_object = TransitionElements(js_object,
4291 FAST_ELEMENTS,
4292 isolate);
4293 if (maybe_object->IsFailure()) return maybe_object;
4294 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004295 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004296 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004297 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4298 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004300 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004301 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004302 if (index >= 0 && index < str->length()) {
4303 Handle<Object> result = GetCharAt(str, index);
4304 return *result;
4305 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004307
4308 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004309 return Runtime::GetObjectProperty(isolate,
4310 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004311 args.at<Object>(1));
4312}
4313
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004314// Implements part of 8.12.9 DefineOwnProperty.
4315// There are 3 cases that lead here:
4316// Step 4b - define a new accessor property.
4317// Steps 9c & 12 - replace an existing data property with an accessor property.
4318// Step 12 - update an existing accessor property with an accessor or generic
4319// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004320RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004321 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004323 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4324 CONVERT_CHECKED(String, name, args[1]);
4325 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004326 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004327 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004328
ager@chromium.org5c838252010-02-19 08:53:10 +00004329 int unchecked = flag_attr->value();
4330 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004332
4333 RUNTIME_ASSERT(!obj->IsNull());
4334 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004335 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4336}
4337
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004338// Implements part of 8.12.9 DefineOwnProperty.
4339// There are 3 cases that lead here:
4340// Step 4a - define a new data property.
4341// Steps 9b & 12 - replace an existing accessor property with a data property.
4342// Step 12 - update an existing data property with a data or generic
4343// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004344RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004346 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004347 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4348 CONVERT_ARG_CHECKED(String, name, 1);
4349 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004351
ager@chromium.org5c838252010-02-19 08:53:10 +00004352 int unchecked = flag->value();
4353 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004354 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4355
4356 // Check if this is an element.
4357 uint32_t index;
4358 bool is_element = name->AsArrayIndex(&index);
4359
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004360 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004361 // If elements are in fast case we always implicitly assume that:
4362 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004363 if (is_element && (attr != NONE ||
4364 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004365 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004366 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004367 // We do not need to do access checks here since these has already
4368 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004369 Handle<Object> proto(js_object->GetPrototype());
4370 // If proxy is detached, ignore the assignment. Alternatively,
4371 // we could throw an exception.
4372 if (proto->IsNull()) return *obj_value;
4373 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004374 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004375
4376 // Don't allow element properties to be redefined on objects with external
4377 // array elements.
4378 if (js_object->HasExternalArrayElements()) {
4379 Handle<Object> args[2] = { js_object, name };
4380 Handle<Object> error =
4381 isolate->factory()->NewTypeError("redef_external_array_element",
4382 HandleVector(args, 2));
4383 return isolate->Throw(*error);
4384 }
4385
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004386 Handle<SeededNumberDictionary> dictionary =
4387 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004388 // Make sure that we never go back to fast case.
4389 dictionary->set_requires_slow_elements();
4390 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004391 Handle<SeededNumberDictionary> extended_dictionary =
4392 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004393 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004394 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004395 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4396 } else {
4397 js_object->set_elements(*extended_dictionary);
4398 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004399 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004400 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004401 }
4402
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004403 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004404 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004405
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004406 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004407 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004408 Object* callback = result.GetCallbackObject();
4409 // To be compatible with Safari we do not change the value on API objects
4410 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4411 // the value.
4412 if (callback->IsAccessorInfo()) {
4413 return isolate->heap()->undefined_value();
4414 }
4415 // Avoid redefining foreign callback as data property, just use the stored
4416 // setter to update the value instead.
4417 // TODO(mstarzinger): So far this only works if property attributes don't
4418 // change, this should be fixed once we cleanup the underlying code.
4419 if (callback->IsForeign() && result.GetAttributes() == attr) {
4420 return js_object->SetPropertyWithCallback(callback,
4421 *name,
4422 *obj_value,
4423 result.holder(),
4424 kStrictMode);
4425 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004426 }
4427
ager@chromium.org5c838252010-02-19 08:53:10 +00004428 // Take special care when attributes are different and there is already
4429 // a property. For simplicity we normalize the property which enables us
4430 // to not worry about changing the instance_descriptor and creating a new
4431 // map. The current version of SetObjectProperty does not handle attributes
4432 // correctly in the case where a property is a field and is reset with
4433 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004434 if (result.IsProperty() &&
4435 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004436 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004437 if (js_object->IsJSGlobalProxy()) {
4438 // Since the result is a property, the prototype will exist so
4439 // we don't have to check for null.
4440 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004441 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004442 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004443 // Use IgnoreAttributes version since a readonly property may be
4444 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004445 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4446 *obj_value,
4447 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004448 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 return Runtime::ForceSetObjectProperty(isolate,
4451 js_object,
4452 name,
4453 obj_value,
4454 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004455}
4456
4457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004458// Special case for elements if any of the flags are true.
4459// If elements are in fast case we always implicitly assume that:
4460// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4461static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4462 Handle<JSObject> js_object,
4463 uint32_t index,
4464 Handle<Object> value,
4465 PropertyAttributes attr) {
4466 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004467 Handle<SeededNumberDictionary> dictionary =
4468 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004469 // Make sure that we never go back to fast case.
4470 dictionary->set_requires_slow_elements();
4471 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004472 Handle<SeededNumberDictionary> extended_dictionary =
4473 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004474 if (*extended_dictionary != *dictionary) {
4475 js_object->set_elements(*extended_dictionary);
4476 }
4477 return *value;
4478}
4479
4480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4482 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004483 Handle<Object> key,
4484 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004485 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004486 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004490 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004491 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 isolate->factory()->NewTypeError("non_object_property_store",
4493 HandleVector(args, 2));
4494 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 }
4496
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004497 if (object->IsJSProxy()) {
4498 bool has_pending_exception = false;
4499 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4500 if (has_pending_exception) return Failure::Exception();
4501 return JSProxy::cast(*object)->SetProperty(
4502 String::cast(*name), *value, attr, strict_mode);
4503 }
4504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505 // If the object isn't a JavaScript object, we ignore the store.
4506 if (!object->IsJSObject()) return *value;
4507
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004508 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004510 // Check if the given key is an array index.
4511 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004512 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4514 // of a string using [] notation. We need to support this too in
4515 // JavaScript.
4516 // In the case of a String object we just need to redirect the assignment to
4517 // the underlying string if the index is in range. Since the underlying
4518 // string does nothing with the assignment then we can ignore such
4519 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004522 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004524 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4525 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4526 }
4527
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004528 Handle<Object> result =
4529 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004530 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 return *value;
4532 }
4533
4534 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004535 Handle<Object> result;
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004537 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4538 return NormalizeObjectSetElement(isolate,
4539 js_object,
4540 index,
4541 value,
4542 attr);
4543 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004544 result =
4545 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004547 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004548 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004549 result = JSReceiver::SetProperty(
4550 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004552 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 return *value;
4554 }
4555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 bool has_pending_exception = false;
4558 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4559 if (has_pending_exception) return Failure::Exception();
4560 Handle<String> name = Handle<String>::cast(converted);
4561
4562 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004563 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004565 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 }
4567}
4568
4569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004570MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4571 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004572 Handle<Object> key,
4573 Handle<Object> value,
4574 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576
4577 // Check if the given key is an array index.
4578 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004579 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004580 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4581 // of a string using [] notation. We need to support this too in
4582 // JavaScript.
4583 // In the case of a String object we just need to redirect the assignment to
4584 // the underlying string if the index is in range. Since the underlying
4585 // string does nothing with the assignment then we can ignore such
4586 // assignments.
4587 if (js_object->IsStringObjectWithCharacterAt(index)) {
4588 return *value;
4589 }
4590
whesse@chromium.org7b260152011-06-20 15:33:18 +00004591 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004592 }
4593
4594 if (key->IsString()) {
4595 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004596 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004597 } else {
4598 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004599 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004600 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4601 *value,
4602 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004603 }
4604 }
4605
4606 // Call-back into JavaScript to convert the key to a string.
4607 bool has_pending_exception = false;
4608 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4609 if (has_pending_exception) return Failure::Exception();
4610 Handle<String> name = Handle<String>::cast(converted);
4611
4612 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004613 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004614 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004615 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004616 }
4617}
4618
4619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004621 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004622 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004624
4625 // Check if the given key is an array index.
4626 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004627 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004628 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4629 // characters of a string using [] notation. In the case of a
4630 // String object we just need to redirect the deletion to the
4631 // underlying string if the index is in range. Since the
4632 // underlying string does nothing with the deletion, we can ignore
4633 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004634 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004635 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004636 }
4637
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004638 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004639 }
4640
4641 Handle<String> key_string;
4642 if (key->IsString()) {
4643 key_string = Handle<String>::cast(key);
4644 } else {
4645 // Call-back into JavaScript to convert the key to a string.
4646 bool has_pending_exception = false;
4647 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4648 if (has_pending_exception) return Failure::Exception();
4649 key_string = Handle<String>::cast(converted);
4650 }
4651
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004652 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004653 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004654}
4655
4656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004657RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004659 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660
4661 Handle<Object> object = args.at<Object>(0);
4662 Handle<Object> key = args.at<Object>(1);
4663 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004664 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004665 RUNTIME_ASSERT(
4666 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004668 PropertyAttributes attributes =
4669 static_cast<PropertyAttributes>(unchecked_attributes);
4670
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004671 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004672 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4674 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 return Runtime::SetObjectProperty(isolate,
4678 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004679 key,
4680 value,
4681 attributes,
4682 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683}
4684
4685
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4687 NoHandleAllocation ha;
4688 RUNTIME_ASSERT(args.length() == 1);
4689 Handle<Object> object = args.at<Object>(0);
4690 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4691}
4692
4693
4694RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4695 NoHandleAllocation ha;
4696 RUNTIME_ASSERT(args.length() == 1);
4697 Handle<Object> object = args.at<Object>(0);
4698 return TransitionElements(object, FAST_ELEMENTS, isolate);
4699}
4700
4701
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004702// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004703// This is used to decide if we should transform null and undefined
4704// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004705RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004706 NoHandleAllocation ha;
4707 RUNTIME_ASSERT(args.length() == 1);
4708
4709 Handle<Object> object = args.at<Object>(0);
4710
4711 if (object->IsJSFunction()) {
4712 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004713 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004714 }
4715 return isolate->heap()->undefined_value();
4716}
4717
4718
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004719RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4720 RUNTIME_ASSERT(args.length() == 5);
4721 CONVERT_ARG_CHECKED(JSObject, object, 0);
4722 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4723 Handle<Object> value = args.at<Object>(2);
4724 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4725 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4726 HandleScope scope;
4727
4728 Object* raw_boilerplate_object = literals->get(literal_index);
4729 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4730#if DEBUG
4731 ElementsKind elements_kind = object->GetElementsKind();
4732#endif
4733 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4734 // Smis should never trigger transitions.
4735 ASSERT(!value->IsSmi());
4736
4737 if (value->IsNumber()) {
4738 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004739 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4740 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004741 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4742 FixedDoubleArray* double_array =
4743 FixedDoubleArray::cast(object->elements());
4744 HeapNumber* number = HeapNumber::cast(*value);
4745 double_array->set(store_index, number->Number());
4746 } else {
4747 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4748 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004749 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4750 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004751 FixedArray* object_array =
4752 FixedArray::cast(object->elements());
4753 object_array->set(store_index, *value);
4754 }
4755 return *object;
4756}
4757
4758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759// Set a local property, even if it is READ_ONLY. If the property does not
4760// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004761RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004763 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 CONVERT_CHECKED(JSObject, object, args[0]);
4765 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004766 // Compute attributes.
4767 PropertyAttributes attributes = NONE;
4768 if (args.length() == 4) {
4769 CONVERT_CHECKED(Smi, value_obj, args[3]);
4770 int unchecked_value = value_obj->value();
4771 // Only attribute bits should be set.
4772 RUNTIME_ASSERT(
4773 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4774 attributes = static_cast<PropertyAttributes>(unchecked_value);
4775 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004777 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004778 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004782RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004784 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004786 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004788 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4789 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004790 ? JSReceiver::STRICT_DELETION
4791 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792}
4793
4794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795static Object* HasLocalPropertyImplementation(Isolate* isolate,
4796 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004797 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004798 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004799 // Handle hidden prototypes. If there's a hidden prototype above this thing
4800 // then we have to check it for properties, because they are supposed to
4801 // look like they are on this object.
4802 Handle<Object> proto(object->GetPrototype());
4803 if (proto->IsJSObject() &&
4804 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 return HasLocalPropertyImplementation(isolate,
4806 Handle<JSObject>::cast(proto),
4807 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004808 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004809 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004810}
4811
4812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004813RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 NoHandleAllocation ha;
4815 ASSERT(args.length() == 2);
4816 CONVERT_CHECKED(String, key, args[1]);
4817
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004818 uint32_t index;
4819 const bool key_is_array_index = key->AsArrayIndex(&index);
4820
ager@chromium.org9085a012009-05-11 19:22:57 +00004821 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004823 if (obj->IsJSObject()) {
4824 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004825 // Fast case: either the key is a real named property or it is not
4826 // an array index and there are no interceptors or hidden
4827 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004828 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004829 Map* map = object->map();
4830 if (!key_is_array_index &&
4831 !map->has_named_interceptor() &&
4832 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4833 return isolate->heap()->false_value();
4834 }
4835 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004836 HandleScope scope(isolate);
4837 return HasLocalPropertyImplementation(isolate,
4838 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004839 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004840 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004842 String* string = String::cast(obj);
4843 if (index < static_cast<uint32_t>(string->length())) {
4844 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845 }
4846 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848}
4849
4850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004851RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 NoHandleAllocation na;
4853 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004854 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4855 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 bool result = receiver->HasProperty(key);
4858 if (isolate->has_pending_exception()) return Failure::Exception();
4859 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860}
4861
4862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004863RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 NoHandleAllocation na;
4865 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004866 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4867 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004869 bool result = receiver->HasElement(index->value());
4870 if (isolate->has_pending_exception()) return Failure::Exception();
4871 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872}
4873
4874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004875RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876 NoHandleAllocation ha;
4877 ASSERT(args.length() == 2);
4878
4879 CONVERT_CHECKED(JSObject, object, args[0]);
4880 CONVERT_CHECKED(String, key, args[1]);
4881
4882 uint32_t index;
4883 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004884 JSObject::LocalElementType type = object->HasLocalElement(index);
4885 switch (type) {
4886 case JSObject::UNDEFINED_ELEMENT:
4887 case JSObject::STRING_CHARACTER_ELEMENT:
4888 return isolate->heap()->false_value();
4889 case JSObject::INTERCEPTED_ELEMENT:
4890 case JSObject::FAST_ELEMENT:
4891 return isolate->heap()->true_value();
4892 case JSObject::DICTIONARY_ELEMENT: {
4893 if (object->IsJSGlobalProxy()) {
4894 Object* proto = object->GetPrototype();
4895 if (proto->IsNull()) {
4896 return isolate->heap()->false_value();
4897 }
4898 ASSERT(proto->IsJSGlobalObject());
4899 object = JSObject::cast(proto);
4900 }
4901 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004902 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004903 if (elements->map() ==
4904 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004905 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004906 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004907 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004908 }
4909 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004910 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004911 PropertyDetails details = dictionary->DetailsAt(entry);
4912 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4913 }
4914 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 }
4916
ager@chromium.org870a0b62008-11-04 11:43:05 +00004917 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919}
4920
4921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004925 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4926 bool threw = false;
4927 Handle<JSArray> result = GetKeysFor(object, &threw);
4928 if (threw) return Failure::Exception();
4929 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930}
4931
4932
4933// Returns either a FixedArray as Runtime_GetPropertyNames,
4934// or, if the given object has an enum cache that contains
4935// all enumerable properties of the object and its prototypes
4936// have none, the map of the object. This is used to speed up
4937// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004938RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 ASSERT(args.length() == 1);
4940
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004941 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942
4943 if (raw_object->IsSimpleEnum()) return raw_object->map();
4944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004945 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004946 Handle<JSReceiver> object(raw_object);
4947 bool threw = false;
4948 Handle<FixedArray> content =
4949 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4950 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004951
4952 // Test again, since cache may have been built by preceding call.
4953 if (object->IsSimpleEnum()) return object->map();
4954
4955 return *content;
4956}
4957
4958
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004959// Find the length of the prototype chain that is to to handled as one. If a
4960// prototype object is hidden it is to be viewed as part of the the object it
4961// is prototype for.
4962static int LocalPrototypeChainLength(JSObject* obj) {
4963 int count = 1;
4964 Object* proto = obj->GetPrototype();
4965 while (proto->IsJSObject() &&
4966 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4967 count++;
4968 proto = JSObject::cast(proto)->GetPrototype();
4969 }
4970 return count;
4971}
4972
4973
4974// Return the names of the local named properties.
4975// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004978 ASSERT(args.length() == 1);
4979 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004980 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 }
4982 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4983
4984 // Skip the global proxy as it has no properties and always delegates to the
4985 // real global object.
4986 if (obj->IsJSGlobalProxy()) {
4987 // Only collect names if access is permitted.
4988 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 !isolate->MayNamedAccess(*obj,
4990 isolate->heap()->undefined_value(),
4991 v8::ACCESS_KEYS)) {
4992 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4993 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994 }
4995 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4996 }
4997
4998 // Find the number of objects making up this.
4999 int length = LocalPrototypeChainLength(*obj);
5000
5001 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005002 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003 int total_property_count = 0;
5004 Handle<JSObject> jsproto = obj;
5005 for (int i = 0; i < length; i++) {
5006 // Only collect names if access is permitted.
5007 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005008 !isolate->MayNamedAccess(*jsproto,
5009 isolate->heap()->undefined_value(),
5010 v8::ACCESS_KEYS)) {
5011 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5012 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005013 }
5014 int n;
5015 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
5016 local_property_count[i] = n;
5017 total_property_count += n;
5018 if (i < length - 1) {
5019 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5020 }
5021 }
5022
5023 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 Handle<FixedArray> names =
5025 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005026
5027 // Get the property names.
5028 jsproto = obj;
5029 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005030 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005031 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005032 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5033 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005034 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005035 proto_with_hidden_properties++;
5036 }
5037 if (i < length - 1) {
5038 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5039 }
5040 }
5041
5042 // Filter out name of hidden propeties object.
5043 if (proto_with_hidden_properties > 0) {
5044 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046 names->length() - proto_with_hidden_properties);
5047 int dest_pos = 0;
5048 for (int i = 0; i < total_property_count; i++) {
5049 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005050 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005051 continue;
5052 }
5053 names->set(dest_pos++, name);
5054 }
5055 }
5056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005058}
5059
5060
5061// Return the names of the local indexed properties.
5062// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005063RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065 ASSERT(args.length() == 1);
5066 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005068 }
5069 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5070
5071 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005073 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005075}
5076
5077
5078// Return information on whether an object has a named or indexed interceptor.
5079// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005080RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005082 ASSERT(args.length() == 1);
5083 if (!args[0]->IsJSObject()) {
5084 return Smi::FromInt(0);
5085 }
5086 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5087
5088 int result = 0;
5089 if (obj->HasNamedInterceptor()) result |= 2;
5090 if (obj->HasIndexedInterceptor()) result |= 1;
5091
5092 return Smi::FromInt(result);
5093}
5094
5095
5096// Return property names from named interceptor.
5097// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005098RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005099 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005100 ASSERT(args.length() == 1);
5101 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5102
5103 if (obj->HasNamedInterceptor()) {
5104 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5105 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5106 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005108}
5109
5110
5111// Return element names from indexed interceptor.
5112// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005115 ASSERT(args.length() == 1);
5116 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5117
5118 if (obj->HasIndexedInterceptor()) {
5119 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5120 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5121 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005123}
5124
5125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005126RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005127 ASSERT_EQ(args.length(), 1);
5128 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005130 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005131
5132 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005133 // Do access checks before going to the global object.
5134 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005136 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005137 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5138 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005139 }
5140
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005141 Handle<Object> proto(object->GetPrototype());
5142 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005144 object = Handle<JSObject>::cast(proto);
5145 }
5146
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005147 bool threw = false;
5148 Handle<FixedArray> contents =
5149 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5150 if (threw) return Failure::Exception();
5151
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005152 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5153 // property array and since the result is mutable we have to create
5154 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005155 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005157 for (int i = 0; i < length; i++) {
5158 Object* entry = contents->get(i);
5159 if (entry->IsString()) {
5160 copy->set(i, entry);
5161 } else {
5162 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005163 HandleScope scope(isolate);
5164 Handle<Object> entry_handle(entry, isolate);
5165 Handle<Object> entry_str =
5166 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005167 copy->set(i, *entry_str);
5168 }
5169 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005171}
5172
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176 ASSERT(args.length() == 1);
5177
5178 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005179 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180 it.AdvanceToArgumentsFrame();
5181 JavaScriptFrame* frame = it.frame();
5182
5183 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005184 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185
5186 // Try to convert the key to an index. If successful and within
5187 // index return the the argument from the frame.
5188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005189 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 return frame->GetParameter(index);
5191 }
5192
5193 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 bool exception = false;
5196 Handle<Object> converted =
5197 Execution::ToString(args.at<Object>(0), &exception);
5198 if (exception) return Failure::Exception();
5199 Handle<String> key = Handle<String>::cast(converted);
5200
5201 // Try to convert the string key into an array index.
5202 if (key->AsArrayIndex(&index)) {
5203 if (index < n) {
5204 return frame->GetParameter(index);
5205 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207 }
5208 }
5209
5210 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5212 if (key->Equals(isolate->heap()->callee_symbol())) {
5213 Object* function = frame->function();
5214 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005215 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 return isolate->Throw(*isolate->factory()->NewTypeError(
5217 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5218 }
5219 return function;
5220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221
5222 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005228 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005229 Object* object = args[0];
5230 return (object->IsJSObject() && !object->IsGlobalObject())
5231 ? JSObject::cast(object)->TransformToFastProperties(0)
5232 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005233}
5234
5235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005236RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005237 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005238 Object* obj = args[0];
5239 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5240 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5241 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005242}
5243
5244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005245RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 NoHandleAllocation ha;
5247 ASSERT(args.length() == 1);
5248
5249 return args[0]->ToBoolean();
5250}
5251
5252
5253// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5254// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005255RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256 NoHandleAllocation ha;
5257
5258 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005259 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 HeapObject* heap_obj = HeapObject::cast(obj);
5261
5262 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 if (heap_obj->map()->is_undetectable()) {
5264 return isolate->heap()->undefined_symbol();
5265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266
5267 InstanceType instance_type = heap_obj->map()->instance_type();
5268 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005269 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005270 }
5271
5272 switch (instance_type) {
5273 case ODDBALL_TYPE:
5274 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005276 }
5277 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005278 return FLAG_harmony_typeof
5279 ? isolate->heap()->null_symbol()
5280 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
5282 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005284 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005285 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 default:
5288 // For any kind of object not handled above, the spec rule for
5289 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291 }
5292}
5293
5294
lrn@chromium.org25156de2010-04-06 13:10:27 +00005295static bool AreDigits(const char*s, int from, int to) {
5296 for (int i = from; i < to; i++) {
5297 if (s[i] < '0' || s[i] > '9') return false;
5298 }
5299
5300 return true;
5301}
5302
5303
5304static int ParseDecimalInteger(const char*s, int from, int to) {
5305 ASSERT(to - from < 10); // Overflow is not possible.
5306 ASSERT(from < to);
5307 int d = s[from] - '0';
5308
5309 for (int i = from + 1; i < to; i++) {
5310 d = 10 * d + (s[i] - '0');
5311 }
5312
5313 return d;
5314}
5315
5316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 1);
5320 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005321 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005322
5323 // Fast case: short integer or some sorts of junk values.
5324 int len = subject->length();
5325 if (subject->IsSeqAsciiString()) {
5326 if (len == 0) return Smi::FromInt(0);
5327
5328 char const* data = SeqAsciiString::cast(subject)->GetChars();
5329 bool minus = (data[0] == '-');
5330 int start_pos = (minus ? 1 : 0);
5331
5332 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005333 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005334 } else if (data[start_pos] > '9') {
5335 // Fast check for a junk value. A valid string may start from a
5336 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5337 // the 'I' character ('Infinity'). All of that have codes not greater than
5338 // '9' except 'I'.
5339 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005340 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005341 }
5342 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5343 // The maximal/minimal smi has 10 digits. If the string has less digits we
5344 // know it will fit into the smi-data type.
5345 int d = ParseDecimalInteger(data, start_pos, len);
5346 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005347 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005348 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005349 } else if (!subject->HasHashCode() &&
5350 len <= String::kMaxArrayIndexSize &&
5351 (len == 1 || data[0] != '0')) {
5352 // String hash is not calculated yet but all the data are present.
5353 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005354 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005355#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005356 subject->Hash(); // Force hash calculation.
5357 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5358 static_cast<int>(hash));
5359#endif
5360 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005361 }
5362 return Smi::FromInt(d);
5363 }
5364 }
5365
5366 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005367 return isolate->heap()->NumberFromDouble(
5368 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369}
5370
5371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005372RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 NoHandleAllocation ha;
5374 ASSERT(args.length() == 1);
5375
5376 CONVERT_CHECKED(JSArray, codes, args[0]);
5377 int length = Smi::cast(codes->length())->value();
5378
5379 // Check if the string can be ASCII.
5380 int i;
5381 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382 Object* element;
5383 { MaybeObject* maybe_element = codes->GetElement(i);
5384 // We probably can't get an exception here, but just in order to enforce
5385 // the checking of inputs in the runtime calls we check here.
5386 if (!maybe_element->ToObject(&element)) return maybe_element;
5387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5389 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5390 break;
5391 }
5392
lrn@chromium.org303ada72010-10-27 09:33:13 +00005393 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005397 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 }
5399
lrn@chromium.org303ada72010-10-27 09:33:13 +00005400 Object* object = NULL;
5401 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 String* result = String::cast(object);
5403 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005404 Object* element;
5405 { MaybeObject* maybe_element = codes->GetElement(i);
5406 if (!maybe_element->ToObject(&element)) return maybe_element;
5407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005409 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005410 }
5411 return result;
5412}
5413
5414
5415// kNotEscaped is generated by the following:
5416//
5417// #!/bin/perl
5418// for (my $i = 0; $i < 256; $i++) {
5419// print "\n" if $i % 16 == 0;
5420// my $c = chr($i);
5421// my $escaped = 1;
5422// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5423// print $escaped ? "0, " : "1, ";
5424// }
5425
5426
5427static bool IsNotEscaped(uint16_t character) {
5428 // Only for 8 bit characters, the rest are always escaped (in a different way)
5429 ASSERT(character < 256);
5430 static const char kNotEscaped[256] = {
5431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5437 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5447 };
5448 return kNotEscaped[character] != 0;
5449}
5450
5451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005452RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453 const char hex_chars[] = "0123456789ABCDEF";
5454 NoHandleAllocation ha;
5455 ASSERT(args.length() == 1);
5456 CONVERT_CHECKED(String, source, args[0]);
5457
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005458 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459
5460 int escaped_length = 0;
5461 int length = source->length();
5462 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005463 Access<StringInputBuffer> buffer(
5464 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 buffer->Reset(source);
5466 while (buffer->has_more()) {
5467 uint16_t character = buffer->GetNext();
5468 if (character >= 256) {
5469 escaped_length += 6;
5470 } else if (IsNotEscaped(character)) {
5471 escaped_length++;
5472 } else {
5473 escaped_length += 3;
5474 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005475 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005476 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005477 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005478 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 return Failure::OutOfMemoryException();
5480 }
5481 }
5482 }
5483 // No length change implies no change. Return original string if no change.
5484 if (escaped_length == length) {
5485 return source;
5486 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005487 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005488 { MaybeObject* maybe_o =
5489 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005490 if (!maybe_o->ToObject(&o)) return maybe_o;
5491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 String* destination = String::cast(o);
5493 int dest_position = 0;
5494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005495 Access<StringInputBuffer> buffer(
5496 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 buffer->Rewind();
5498 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005499 uint16_t chr = buffer->GetNext();
5500 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 destination->Set(dest_position, '%');
5502 destination->Set(dest_position+1, 'u');
5503 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5504 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5505 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5506 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005508 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 dest_position++;
5511 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005512 destination->Set(dest_position, '%');
5513 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5514 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 dest_position += 3;
5516 }
5517 }
5518 return destination;
5519}
5520
5521
5522static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5523 static const signed char kHexValue['g'] = {
5524 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5525 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5528 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5529 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5530 -1, 10, 11, 12, 13, 14, 15 };
5531
5532 if (character1 > 'f') return -1;
5533 int hi = kHexValue[character1];
5534 if (hi == -1) return -1;
5535 if (character2 > 'f') return -1;
5536 int lo = kHexValue[character2];
5537 if (lo == -1) return -1;
5538 return (hi << 4) + lo;
5539}
5540
5541
ager@chromium.org870a0b62008-11-04 11:43:05 +00005542static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005543 int i,
5544 int length,
5545 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005546 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005547 int32_t hi = 0;
5548 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 if (character == '%' &&
5550 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005551 source->Get(i + 1) == 'u' &&
5552 (hi = TwoDigitHex(source->Get(i + 2),
5553 source->Get(i + 3))) != -1 &&
5554 (lo = TwoDigitHex(source->Get(i + 4),
5555 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 *step = 6;
5557 return (hi << 8) + lo;
5558 } else if (character == '%' &&
5559 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005560 (lo = TwoDigitHex(source->Get(i + 1),
5561 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 *step = 3;
5563 return lo;
5564 } else {
5565 *step = 1;
5566 return character;
5567 }
5568}
5569
5570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005571RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 NoHandleAllocation ha;
5573 ASSERT(args.length() == 1);
5574 CONVERT_CHECKED(String, source, args[0]);
5575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005576 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
5578 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580
5581 int unescaped_length = 0;
5582 for (int i = 0; i < length; unescaped_length++) {
5583 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005584 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 i += step;
5588 }
5589
5590 // No length change implies no change. Return original string if no change.
5591 if (unescaped_length == length)
5592 return source;
5593
lrn@chromium.org303ada72010-10-27 09:33:13 +00005594 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595 { MaybeObject* maybe_o =
5596 ascii ?
5597 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5598 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005599 if (!maybe_o->ToObject(&o)) return maybe_o;
5600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 String* destination = String::cast(o);
5602
5603 int dest_position = 0;
5604 for (int i = 0; i < length; dest_position++) {
5605 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005606 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 i += step;
5608 }
5609 return destination;
5610}
5611
5612
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005613static const unsigned int kQuoteTableLength = 128u;
5614
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005615static const int kJsonQuotesCharactersPerEntry = 8;
5616static const char* const JsonQuotes =
5617 "\\u0000 \\u0001 \\u0002 \\u0003 "
5618 "\\u0004 \\u0005 \\u0006 \\u0007 "
5619 "\\b \\t \\n \\u000b "
5620 "\\f \\r \\u000e \\u000f "
5621 "\\u0010 \\u0011 \\u0012 \\u0013 "
5622 "\\u0014 \\u0015 \\u0016 \\u0017 "
5623 "\\u0018 \\u0019 \\u001a \\u001b "
5624 "\\u001c \\u001d \\u001e \\u001f "
5625 " ! \\\" # "
5626 "$ % & ' "
5627 "( ) * + "
5628 ", - . / "
5629 "0 1 2 3 "
5630 "4 5 6 7 "
5631 "8 9 : ; "
5632 "< = > ? "
5633 "@ A B C "
5634 "D E F G "
5635 "H I J K "
5636 "L M N O "
5637 "P Q R S "
5638 "T U V W "
5639 "X Y Z [ "
5640 "\\\\ ] ^ _ "
5641 "` a b c "
5642 "d e f g "
5643 "h i j k "
5644 "l m n o "
5645 "p q r s "
5646 "t u v w "
5647 "x y z { "
5648 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005649
5650
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005651// For a string that is less than 32k characters it should always be
5652// possible to allocate it in new space.
5653static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5654
5655
5656// Doing JSON quoting cannot make the string more than this many times larger.
5657static const int kJsonQuoteWorstCaseBlowup = 6;
5658
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005659static const int kSpaceForQuotesAndComma = 3;
5660static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005661
5662// Covers the entire ASCII range (all other characters are unchanged by JSON
5663// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664static const byte JsonQuoteLengths[kQuoteTableLength] = {
5665 6, 6, 6, 6, 6, 6, 6, 6,
5666 2, 2, 2, 6, 2, 2, 6, 6,
5667 6, 6, 6, 6, 6, 6, 6, 6,
5668 6, 6, 6, 6, 6, 6, 6, 6,
5669 1, 1, 2, 1, 1, 1, 1, 1,
5670 1, 1, 1, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 1, 1, 1, 1,
5674 1, 1, 1, 1, 1, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 2, 1, 1, 1,
5677 1, 1, 1, 1, 1, 1, 1, 1,
5678 1, 1, 1, 1, 1, 1, 1, 1,
5679 1, 1, 1, 1, 1, 1, 1, 1,
5680 1, 1, 1, 1, 1, 1, 1, 1,
5681};
5682
5683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005684template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005685MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005686
5687
5688template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005689MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5690 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005691}
5692
5693
5694template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5696 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005697}
5698
5699
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005700template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005701static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5702 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005703 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005704 const Char* read_cursor = characters.start();
5705 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005706 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005707 int quoted_length = kSpaceForQuotes;
5708 while (read_cursor < end) {
5709 Char c = *(read_cursor++);
5710 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5711 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005712 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005713 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005714 }
5715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005716 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5717 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005718 Object* new_object;
5719 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005720 return new_alloc;
5721 }
5722 StringType* new_string = StringType::cast(new_object);
5723
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005724 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005725 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005726 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005727 *(write_cursor++) = '"';
5728
5729 read_cursor = characters.start();
5730 while (read_cursor < end) {
5731 Char c = *(read_cursor++);
5732 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5733 *(write_cursor++) = c;
5734 } else {
5735 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5736 const char* replacement = JsonQuotes +
5737 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5738 for (int i = 0; i < len; i++) {
5739 *write_cursor++ = *replacement++;
5740 }
5741 }
5742 }
5743 *(write_cursor++) = '"';
5744 return new_string;
5745}
5746
5747
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005748template <typename SinkChar, typename SourceChar>
5749static inline SinkChar* WriteQuoteJsonString(
5750 Isolate* isolate,
5751 SinkChar* write_cursor,
5752 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005753 // SinkChar is only char if SourceChar is guaranteed to be char.
5754 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005755 const SourceChar* read_cursor = characters.start();
5756 const SourceChar* end = read_cursor + characters.length();
5757 *(write_cursor++) = '"';
5758 while (read_cursor < end) {
5759 SourceChar c = *(read_cursor++);
5760 if (sizeof(SourceChar) > 1u &&
5761 static_cast<unsigned>(c) >= kQuoteTableLength) {
5762 *(write_cursor++) = static_cast<SinkChar>(c);
5763 } else {
5764 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5765 const char* replacement = JsonQuotes +
5766 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5767 write_cursor[0] = replacement[0];
5768 if (len > 1) {
5769 write_cursor[1] = replacement[1];
5770 if (len > 2) {
5771 ASSERT(len == 6);
5772 write_cursor[2] = replacement[2];
5773 write_cursor[3] = replacement[3];
5774 write_cursor[4] = replacement[4];
5775 write_cursor[5] = replacement[5];
5776 }
5777 }
5778 write_cursor += len;
5779 }
5780 }
5781 *(write_cursor++) = '"';
5782 return write_cursor;
5783}
5784
5785
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005786template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787static MaybeObject* QuoteJsonString(Isolate* isolate,
5788 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005789 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005791 int worst_case_length =
5792 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005793 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005795 }
5796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5798 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005799 Object* new_object;
5800 if (!new_alloc->ToObject(&new_object)) {
5801 return new_alloc;
5802 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005803 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005804 // Even if our string is small enough to fit in new space we still have to
5805 // handle it being allocated in old space as may happen in the third
5806 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5807 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005808 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005809 }
5810 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005813 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005814 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005815 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005816 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5817 write_cursor,
5818 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005819 int final_length = static_cast<int>(
5820 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005821 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005822 isolate->heap()->new_space()->
5823 template ShrinkStringAtAllocationBoundary<StringType>(
5824 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005825 return new_string;
5826}
5827
5828
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005829RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005830 NoHandleAllocation ha;
5831 CONVERT_CHECKED(String, str, args[0]);
5832 if (!str->IsFlat()) {
5833 MaybeObject* try_flatten = str->TryFlatten();
5834 Object* flat;
5835 if (!try_flatten->ToObject(&flat)) {
5836 return try_flatten;
5837 }
5838 str = String::cast(flat);
5839 ASSERT(str->IsFlat());
5840 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005841 String::FlatContent flat = str->GetFlatContent();
5842 ASSERT(flat.IsFlat());
5843 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005845 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005846 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005848 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005849 }
5850}
5851
5852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005853RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005854 NoHandleAllocation ha;
5855 CONVERT_CHECKED(String, str, args[0]);
5856 if (!str->IsFlat()) {
5857 MaybeObject* try_flatten = str->TryFlatten();
5858 Object* flat;
5859 if (!try_flatten->ToObject(&flat)) {
5860 return try_flatten;
5861 }
5862 str = String::cast(flat);
5863 ASSERT(str->IsFlat());
5864 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005865 String::FlatContent flat = str->GetFlatContent();
5866 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005868 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005869 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005871 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005872 }
5873}
5874
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005875
5876template <typename Char, typename StringType>
5877static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5878 FixedArray* array,
5879 int worst_case_length) {
5880 int length = array->length();
5881
5882 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5883 worst_case_length);
5884 Object* new_object;
5885 if (!new_alloc->ToObject(&new_object)) {
5886 return new_alloc;
5887 }
5888 if (!isolate->heap()->new_space()->Contains(new_object)) {
5889 // Even if our string is small enough to fit in new space we still have to
5890 // handle it being allocated in old space as may happen in the third
5891 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5892 // CEntryStub::GenerateCore.
5893 return isolate->heap()->undefined_value();
5894 }
5895 AssertNoAllocation no_gc;
5896 StringType* new_string = StringType::cast(new_object);
5897 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5898
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005899 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005900 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005901 *(write_cursor++) = '[';
5902 for (int i = 0; i < length; i++) {
5903 if (i != 0) *(write_cursor++) = ',';
5904 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005905 String::FlatContent content = str->GetFlatContent();
5906 ASSERT(content.IsFlat());
5907 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005908 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5909 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005910 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005911 } else {
5912 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5913 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005914 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005915 }
5916 }
5917 *(write_cursor++) = ']';
5918
5919 int final_length = static_cast<int>(
5920 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005921 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005922 isolate->heap()->new_space()->
5923 template ShrinkStringAtAllocationBoundary<StringType>(
5924 new_string, final_length);
5925 return new_string;
5926}
5927
5928
5929RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 1);
5932 CONVERT_CHECKED(JSArray, array, args[0]);
5933
5934 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5935 FixedArray* elements = FixedArray::cast(array->elements());
5936 int n = elements->length();
5937 bool ascii = true;
5938 int total_length = 0;
5939
5940 for (int i = 0; i < n; i++) {
5941 Object* elt = elements->get(i);
5942 if (!elt->IsString()) return isolate->heap()->undefined_value();
5943 String* element = String::cast(elt);
5944 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5945 total_length += element->length();
5946 if (ascii && element->IsTwoByteRepresentation()) {
5947 ascii = false;
5948 }
5949 }
5950
5951 int worst_case_length =
5952 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5953 + total_length * kJsonQuoteWorstCaseBlowup;
5954
5955 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5956 return isolate->heap()->undefined_value();
5957 }
5958
5959 if (ascii) {
5960 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5961 elements,
5962 worst_case_length);
5963 } else {
5964 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5965 elements,
5966 worst_case_length);
5967 }
5968}
5969
5970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005971RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972 NoHandleAllocation ha;
5973
5974 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005975 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005977 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978
lrn@chromium.org25156de2010-04-06 13:10:27 +00005979 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005980 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982}
5983
5984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005985RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 NoHandleAllocation ha;
5987 CONVERT_CHECKED(String, str, args[0]);
5988
5989 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005990 double value = StringToDouble(isolate->unicode_cache(),
5991 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992
5993 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995}
5996
5997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005999MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006001 String* s,
6002 int length,
6003 int input_string_length,
6004 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006005 // We try this twice, once with the assumption that the result is no longer
6006 // than the input and, if that assumption breaks, again with the exact
6007 // length. This may not be pretty, but it is nicer than what was here before
6008 // and I hereby claim my vaffel-is.
6009 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010 // Allocate the resulting string.
6011 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006012 // NOTE: This assumes that the upper/lower case of an ASCII
6013 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 // might break in the future if we implement more context and locale
6015 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006016 Object* o;
6017 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 ? isolate->heap()->AllocateRawAsciiString(length)
6019 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006020 if (!maybe_o->ToObject(&o)) return maybe_o;
6021 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 String* result = String::cast(o);
6023 bool has_changed_character = false;
6024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 // Convert all characters to upper case, assuming that they will fit
6026 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 Access<StringInputBuffer> buffer(
6028 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006029 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006030 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 // We can assume that the string is not empty
6032 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006034 bool has_next = buffer->has_more();
6035 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036 int char_length = mapping->get(current, next, chars);
6037 if (char_length == 0) {
6038 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006039 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 i++;
6041 } else if (char_length == 1) {
6042 // Common case: converting the letter resulted in one character.
6043 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006044 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045 has_changed_character = true;
6046 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006047 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 // We've assumed that the result would be as long as the
6049 // input but here is a character that converts to several
6050 // characters. No matter, we calculate the exact length
6051 // of the result and try the whole thing again.
6052 //
6053 // Note that this leaves room for optimization. We could just
6054 // memcpy what we already have to the result string. Also,
6055 // the result string is the last object allocated we could
6056 // "realloc" it and probably, in the vast majority of cases,
6057 // extend the existing string to be able to hold the full
6058 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006059 int next_length = 0;
6060 if (has_next) {
6061 next_length = mapping->get(next, 0, chars);
6062 if (next_length == 0) next_length = 1;
6063 }
6064 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 while (buffer->has_more()) {
6066 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006067 // NOTE: we use 0 as the next character here because, while
6068 // the next character may affect what a character converts to,
6069 // it does not in any case affect the length of what it convert
6070 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 int char_length = mapping->get(current, 0, chars);
6072 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006073 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006074 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006075 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006076 return Failure::OutOfMemoryException();
6077 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006079 // Try again with the real length.
6080 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081 } else {
6082 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006083 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084 i++;
6085 }
6086 has_changed_character = true;
6087 }
6088 current = next;
6089 }
6090 if (has_changed_character) {
6091 return result;
6092 } else {
6093 // If we didn't actually change anything in doing the conversion
6094 // we simple return the result and let the converted string
6095 // become garbage; there is no reason to keep two identical strings
6096 // alive.
6097 return s;
6098 }
6099}
6100
6101
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006102namespace {
6103
lrn@chromium.org303ada72010-10-27 09:33:13 +00006104static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6105
6106
6107// Given a word and two range boundaries returns a word with high bit
6108// set in every byte iff the corresponding input byte was strictly in
6109// the range (m, n). All the other bits in the result are cleared.
6110// This function is only useful when it can be inlined and the
6111// boundaries are statically known.
6112// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006113// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006114static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006115 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006116 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6117 // Use strict inequalities since in edge cases the function could be
6118 // further simplified.
6119 ASSERT(0 < m && m < n && n < 0x7F);
6120 // Has high bit set in every w byte less than n.
6121 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6122 // Has high bit set in every w byte greater than m.
6123 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6124 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6125}
6126
6127
6128enum AsciiCaseConversion {
6129 ASCII_TO_LOWER,
6130 ASCII_TO_UPPER
6131};
6132
6133
6134template <AsciiCaseConversion dir>
6135struct FastAsciiConverter {
6136 static bool Convert(char* dst, char* src, int length) {
6137#ifdef DEBUG
6138 char* saved_dst = dst;
6139 char* saved_src = src;
6140#endif
6141 // We rely on the distance between upper and lower case letters
6142 // being a known power of 2.
6143 ASSERT('a' - 'A' == (1 << 5));
6144 // Boundaries for the range of input characters than require conversion.
6145 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6146 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6147 bool changed = false;
6148 char* const limit = src + length;
6149#ifdef V8_HOST_CAN_READ_UNALIGNED
6150 // Process the prefix of the input that requires no conversion one
6151 // (machine) word at a time.
6152 while (src <= limit - sizeof(uintptr_t)) {
6153 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6154 if (AsciiRangeMask(w, lo, hi) != 0) {
6155 changed = true;
6156 break;
6157 }
6158 *reinterpret_cast<uintptr_t*>(dst) = w;
6159 src += sizeof(uintptr_t);
6160 dst += sizeof(uintptr_t);
6161 }
6162 // Process the remainder of the input performing conversion when
6163 // required one word at a time.
6164 while (src <= limit - sizeof(uintptr_t)) {
6165 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6166 uintptr_t m = AsciiRangeMask(w, lo, hi);
6167 // The mask has high (7th) bit set in every byte that needs
6168 // conversion and we know that the distance between cases is
6169 // 1 << 5.
6170 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6171 src += sizeof(uintptr_t);
6172 dst += sizeof(uintptr_t);
6173 }
6174#endif
6175 // Process the last few bytes of the input (or the whole input if
6176 // unaligned access is not supported).
6177 while (src < limit) {
6178 char c = *src;
6179 if (lo < c && c < hi) {
6180 c ^= (1 << 5);
6181 changed = true;
6182 }
6183 *dst = c;
6184 ++src;
6185 ++dst;
6186 }
6187#ifdef DEBUG
6188 CheckConvert(saved_dst, saved_src, length, changed);
6189#endif
6190 return changed;
6191 }
6192
6193#ifdef DEBUG
6194 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6195 bool expected_changed = false;
6196 for (int i = 0; i < length; i++) {
6197 if (dst[i] == src[i]) continue;
6198 expected_changed = true;
6199 if (dir == ASCII_TO_LOWER) {
6200 ASSERT('A' <= src[i] && src[i] <= 'Z');
6201 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6202 } else {
6203 ASSERT(dir == ASCII_TO_UPPER);
6204 ASSERT('a' <= src[i] && src[i] <= 'z');
6205 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6206 }
6207 }
6208 ASSERT(expected_changed == changed);
6209 }
6210#endif
6211};
6212
6213
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006214struct ToLowerTraits {
6215 typedef unibrow::ToLowercase UnibrowConverter;
6216
lrn@chromium.org303ada72010-10-27 09:33:13 +00006217 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218};
6219
6220
6221struct ToUpperTraits {
6222 typedef unibrow::ToUppercase UnibrowConverter;
6223
lrn@chromium.org303ada72010-10-27 09:33:13 +00006224 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006225};
6226
6227} // namespace
6228
6229
6230template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006231MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006235 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006236 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006237 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006240 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241 if (length == 0) return s;
6242
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006243 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006245 // NOTE: This assumes that the upper/lower case of an ASCII
6246 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 // might break in the future if we implement more context and locale
6248 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006249 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006250 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 if (!maybe_o->ToObject(&o)) return maybe_o;
6253 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006256 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257 return has_changed_character ? result : s;
6258 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006259
lrn@chromium.org303ada72010-10-27 09:33:13 +00006260 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 { MaybeObject* maybe_answer =
6262 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006263 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6264 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006265 if (answer->IsSmi()) {
6266 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 ConvertCaseHelper(isolate,
6269 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006270 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6271 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006272 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006273 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006274}
6275
6276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006277RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006278 return ConvertCase<ToLowerTraits>(
6279 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280}
6281
6282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006283RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006284 return ConvertCase<ToUpperTraits>(
6285 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286}
6287
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006288
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006289static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006290 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006291}
6292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006295 NoHandleAllocation ha;
6296 ASSERT(args.length() == 3);
6297
6298 CONVERT_CHECKED(String, s, args[0]);
6299 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6300 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006302 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006303 int length = s->length();
6304
6305 int left = 0;
6306 if (trimLeft) {
6307 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6308 left++;
6309 }
6310 }
6311
6312 int right = length;
6313 if (trimRight) {
6314 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6315 right--;
6316 }
6317 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006318 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006319}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006323 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006324 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006325 CONVERT_ARG_CHECKED(String, subject, 0);
6326 CONVERT_ARG_CHECKED(String, pattern, 1);
6327 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6328
6329 int subject_length = subject->length();
6330 int pattern_length = pattern->length();
6331 RUNTIME_ASSERT(pattern_length > 0);
6332
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006333 if (limit == 0xffffffffu) {
6334 Handle<Object> cached_answer(StringSplitCache::Lookup(
6335 isolate->heap()->string_split_cache(),
6336 *subject,
6337 *pattern));
6338 if (*cached_answer != Smi::FromInt(0)) {
6339 Handle<JSArray> result =
6340 isolate->factory()->NewJSArrayWithElements(
6341 Handle<FixedArray>::cast(cached_answer));
6342 return *result;
6343 }
6344 }
6345
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006346 // The limit can be very large (0xffffffffu), but since the pattern
6347 // isn't empty, we can never create more parts than ~half the length
6348 // of the subject.
6349
6350 if (!subject->IsFlat()) FlattenString(subject);
6351
6352 static const int kMaxInitialListCapacity = 16;
6353
danno@chromium.org40cb8782011-05-25 07:58:50 +00006354 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006355
6356 // Find (up to limit) indices of separator and end-of-string in subject
6357 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6358 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006359 if (!pattern->IsFlat()) FlattenString(pattern);
6360
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006361 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006362
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006363 if (static_cast<uint32_t>(indices.length()) < limit) {
6364 indices.Add(subject_length);
6365 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006366
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006367 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006368
6369 // Create JSArray of substrings separated by separator.
6370 int part_count = indices.length();
6371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006373 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006374 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006375 result->set_length(Smi::FromInt(part_count));
6376
6377 ASSERT(result->HasFastElements());
6378
6379 if (part_count == 1 && indices.at(0) == subject_length) {
6380 FixedArray::cast(result->elements())->set(0, *subject);
6381 return *result;
6382 }
6383
6384 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6385 int part_start = 0;
6386 for (int i = 0; i < part_count; i++) {
6387 HandleScope local_loop_handle;
6388 int part_end = indices.at(i);
6389 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006390 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006391 elements->set(i, *substring);
6392 part_start = part_end + pattern_length;
6393 }
6394
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006395 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006396 if (result->HasFastElements()) {
6397 StringSplitCache::Enter(isolate->heap(),
6398 isolate->heap()->string_split_cache(),
6399 *subject,
6400 *pattern,
6401 *elements);
6402 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006403 }
6404
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006405 return *result;
6406}
6407
6408
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006409// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006410// one-char strings in the cache. Gives up on the first char that is
6411// not in the cache and fills the remainder with smi zeros. Returns
6412// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413static int CopyCachedAsciiCharsToArray(Heap* heap,
6414 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006415 FixedArray* elements,
6416 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006417 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006418 FixedArray* ascii_cache = heap->single_character_string_cache();
6419 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006420 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006421 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422 for (i = 0; i < length; ++i) {
6423 Object* value = ascii_cache->get(chars[i]);
6424 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006425 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006426 }
6427 if (i < length) {
6428 ASSERT(Smi::FromInt(0) == 0);
6429 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6430 }
6431#ifdef DEBUG
6432 for (int j = 0; j < length; ++j) {
6433 Object* element = elements->get(j);
6434 ASSERT(element == Smi::FromInt(0) ||
6435 (element->IsString() && String::cast(element)->LooksValid()));
6436 }
6437#endif
6438 return i;
6439}
6440
6441
6442// Converts a String to JSArray.
6443// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006446 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006447 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006448 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006449
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006450 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006451 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006452
6453 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006454 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006455 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006456 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006457 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 { MaybeObject* maybe_obj =
6459 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006460 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6461 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006463 String::FlatContent content = s->GetFlatContent();
6464 if (content.IsAscii()) {
6465 Vector<const char> chars = content.ToAsciiVector();
6466 // Note, this will initialize all elements (not only the prefix)
6467 // to prevent GC from seeing partially initialized array.
6468 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6469 chars.start(),
6470 *elements,
6471 length);
6472 } else {
6473 MemsetPointer(elements->data_start(),
6474 isolate->heap()->undefined_value(),
6475 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006476 }
6477 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006479 }
6480 for (int i = position; i < length; ++i) {
6481 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6482 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006483 }
6484
6485#ifdef DEBUG
6486 for (int i = 0; i < length; ++i) {
6487 ASSERT(String::cast(elements->get(i))->length() == 1);
6488 }
6489#endif
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498 CONVERT_CHECKED(String, value, args[0]);
6499 return value->ToObject();
6500}
6501
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006504 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006505 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006506 return char_length == 0;
6507}
6508
6509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006510RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511 NoHandleAllocation ha;
6512 ASSERT(args.length() == 1);
6513
6514 Object* number = args[0];
6515 RUNTIME_ASSERT(number->IsNumber());
6516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006518}
6519
6520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006522 NoHandleAllocation ha;
6523 ASSERT(args.length() == 1);
6524
6525 Object* number = args[0];
6526 RUNTIME_ASSERT(number->IsNumber());
6527
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006529}
6530
6531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006536 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006537
6538 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6539 if (number > 0 && number <= Smi::kMaxValue) {
6540 return Smi::FromInt(static_cast<int>(number));
6541 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 1);
6549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006550 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006551
6552 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6553 if (number > 0 && number <= Smi::kMaxValue) {
6554 return Smi::FromInt(static_cast<int>(number));
6555 }
6556
6557 double double_value = DoubleToInteger(number);
6558 // Map both -0 and +0 to +0.
6559 if (double_value == 0) double_value = 0;
6560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006562}
6563
6564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006565RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 NoHandleAllocation ha;
6567 ASSERT(args.length() == 1);
6568
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006570 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006571}
6572
6573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006574RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 1);
6577
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006578 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579
6580 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6581 if (number > 0 && number <= Smi::kMaxValue) {
6582 return Smi::FromInt(static_cast<int>(number));
6583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6589// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006590RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 1);
6593
6594 Object* obj = args[0];
6595 if (obj->IsSmi()) {
6596 return obj;
6597 }
6598 if (obj->IsHeapNumber()) {
6599 double value = HeapNumber::cast(obj)->value();
6600 int int_value = FastD2I(value);
6601 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6602 return Smi::FromInt(int_value);
6603 }
6604 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006606}
6607
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006613}
6614
6615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006616RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
6619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6621 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006626RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 2);
6629
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006630 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6631 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 2);
6639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6641 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006646RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647 NoHandleAllocation ha;
6648 ASSERT(args.length() == 1);
6649
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006650 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 0);
6658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006659 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006660}
6661
6662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006663RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 NoHandleAllocation ha;
6665 ASSERT(args.length() == 2);
6666
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006667 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6668 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006669 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670}
6671
6672
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006673RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674 NoHandleAllocation ha;
6675 ASSERT(args.length() == 2);
6676
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006677 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6678 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679
ager@chromium.org3811b432009-10-28 14:53:37 +00006680 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006681 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683}
6684
6685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006686RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 NoHandleAllocation ha;
6688 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 CONVERT_CHECKED(String, str1, args[0]);
6690 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 isolate->counters()->string_add_runtime()->Increment();
6692 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693}
6694
6695
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006696template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006697static inline void StringBuilderConcatHelper(String* special,
6698 sinkchar* sink,
6699 FixedArray* fixed_array,
6700 int array_length) {
6701 int position = 0;
6702 for (int i = 0; i < array_length; i++) {
6703 Object* element = fixed_array->get(i);
6704 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006705 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006706 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006707 int pos;
6708 int len;
6709 if (encoded_slice > 0) {
6710 // Position and length encoded in one smi.
6711 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6712 len = StringBuilderSubstringLength::decode(encoded_slice);
6713 } else {
6714 // Position and length encoded in two smis.
6715 Object* obj = fixed_array->get(++i);
6716 ASSERT(obj->IsSmi());
6717 pos = Smi::cast(obj)->value();
6718 len = -encoded_slice;
6719 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006720 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006721 sink + position,
6722 pos,
6723 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006724 position += len;
6725 } else {
6726 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006727 int element_length = string->length();
6728 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006729 position += element_length;
6730 }
6731 }
6732}
6733
6734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006735RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006737 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006738 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006739 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006740 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006741 return Failure::OutOfMemoryException();
6742 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006743 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006744 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006745
6746 // This assumption is used by the slice encoding in one or two smis.
6747 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6748
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006749 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006750 if (maybe_result->IsFailure()) return maybe_result;
6751
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006752 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 }
6756 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006757 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760
6761 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 } else if (array_length == 1) {
6764 Object* first = fixed_array->get(0);
6765 if (first->IsString()) return first;
6766 }
6767
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006768 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 int position = 0;
6770 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006771 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 Object* elt = fixed_array->get(i);
6773 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006774 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 int smi_value = Smi::cast(elt)->value();
6776 int pos;
6777 int len;
6778 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006780 pos = StringBuilderSubstringPosition::decode(smi_value);
6781 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006782 } else {
6783 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006784 len = -smi_value;
6785 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006786 i++;
6787 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006789 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006790 Object* next_smi = fixed_array->get(i);
6791 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006792 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006793 }
6794 pos = Smi::cast(next_smi)->value();
6795 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006799 ASSERT(pos >= 0);
6800 ASSERT(len >= 0);
6801 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006802 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006803 }
6804 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 } else if (elt->IsString()) {
6806 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006807 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006808 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006809 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006815 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006817 return Failure::OutOfMemoryException();
6818 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006819 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 }
6821
6822 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006826 { MaybeObject* maybe_object =
6827 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006828 if (!maybe_object->ToObject(&object)) return maybe_object;
6829 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006830 SeqAsciiString* answer = SeqAsciiString::cast(object);
6831 StringBuilderConcatHelper(special,
6832 answer->GetChars(),
6833 fixed_array,
6834 array_length);
6835 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 { MaybeObject* maybe_object =
6838 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006839 if (!maybe_object->ToObject(&object)) return maybe_object;
6840 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006841 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6842 StringBuilderConcatHelper(special,
6843 answer->GetChars(),
6844 fixed_array,
6845 array_length);
6846 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848}
6849
6850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006851RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006852 NoHandleAllocation ha;
6853 ASSERT(args.length() == 3);
6854 CONVERT_CHECKED(JSArray, array, args[0]);
6855 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006856 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006857 return Failure::OutOfMemoryException();
6858 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006859 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006860 CONVERT_CHECKED(String, separator, args[2]);
6861
6862 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006864 }
6865 FixedArray* fixed_array = FixedArray::cast(array->elements());
6866 if (fixed_array->length() < array_length) {
6867 array_length = fixed_array->length();
6868 }
6869
6870 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 } else if (array_length == 1) {
6873 Object* first = fixed_array->get(0);
6874 if (first->IsString()) return first;
6875 }
6876
6877 int separator_length = separator->length();
6878 int max_nof_separators =
6879 (String::kMaxLength + separator_length - 1) / separator_length;
6880 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006881 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006882 return Failure::OutOfMemoryException();
6883 }
6884 int length = (array_length - 1) * separator_length;
6885 for (int i = 0; i < array_length; i++) {
6886 Object* element_obj = fixed_array->get(i);
6887 if (!element_obj->IsString()) {
6888 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006889 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006890 }
6891 String* element = String::cast(element_obj);
6892 int increment = element->length();
6893 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006894 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006895 return Failure::OutOfMemoryException();
6896 }
6897 length += increment;
6898 }
6899
6900 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006901 { MaybeObject* maybe_object =
6902 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006903 if (!maybe_object->ToObject(&object)) return maybe_object;
6904 }
6905 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6906
6907 uc16* sink = answer->GetChars();
6908#ifdef DEBUG
6909 uc16* end = sink + length;
6910#endif
6911
6912 String* first = String::cast(fixed_array->get(0));
6913 int first_length = first->length();
6914 String::WriteToFlat(first, sink, 0, first_length);
6915 sink += first_length;
6916
6917 for (int i = 1; i < array_length; i++) {
6918 ASSERT(sink + separator_length <= end);
6919 String::WriteToFlat(separator, sink, 0, separator_length);
6920 sink += separator_length;
6921
6922 String* element = String::cast(fixed_array->get(i));
6923 int element_length = element->length();
6924 ASSERT(sink + element_length <= end);
6925 String::WriteToFlat(element, sink, 0, element_length);
6926 sink += element_length;
6927 }
6928 ASSERT(sink == end);
6929
6930 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6931 return answer;
6932}
6933
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006934template <typename Char>
6935static void JoinSparseArrayWithSeparator(FixedArray* elements,
6936 int elements_length,
6937 uint32_t array_length,
6938 String* separator,
6939 Vector<Char> buffer) {
6940 int previous_separator_position = 0;
6941 int separator_length = separator->length();
6942 int cursor = 0;
6943 for (int i = 0; i < elements_length; i += 2) {
6944 int position = NumberToInt32(elements->get(i));
6945 String* string = String::cast(elements->get(i + 1));
6946 int string_length = string->length();
6947 if (string->length() > 0) {
6948 while (previous_separator_position < position) {
6949 String::WriteToFlat<Char>(separator, &buffer[cursor],
6950 0, separator_length);
6951 cursor += separator_length;
6952 previous_separator_position++;
6953 }
6954 String::WriteToFlat<Char>(string, &buffer[cursor],
6955 0, string_length);
6956 cursor += string->length();
6957 }
6958 }
6959 if (separator_length > 0) {
6960 // Array length must be representable as a signed 32-bit number,
6961 // otherwise the total string length would have been too large.
6962 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6963 int last_array_index = static_cast<int>(array_length - 1);
6964 while (previous_separator_position < last_array_index) {
6965 String::WriteToFlat<Char>(separator, &buffer[cursor],
6966 0, separator_length);
6967 cursor += separator_length;
6968 previous_separator_position++;
6969 }
6970 }
6971 ASSERT(cursor <= buffer.length());
6972}
6973
6974
6975RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 3);
6978 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006979 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6980 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006981 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6982 CONVERT_CHECKED(String, separator, args[2]);
6983 // elements_array is fast-mode JSarray of alternating positions
6984 // (increasing order) and strings.
6985 // array_length is length of original array (used to add separators);
6986 // separator is string to put between elements. Assumed to be non-empty.
6987
6988 // Find total length of join result.
6989 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006990 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006991 int max_string_length;
6992 if (is_ascii) {
6993 max_string_length = SeqAsciiString::kMaxLength;
6994 } else {
6995 max_string_length = SeqTwoByteString::kMaxLength;
6996 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006997 bool overflow = false;
6998 CONVERT_NUMBER_CHECKED(int, elements_length,
6999 Int32, elements_array->length());
7000 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7001 FixedArray* elements = FixedArray::cast(elements_array->elements());
7002 for (int i = 0; i < elements_length; i += 2) {
7003 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7004 CONVERT_CHECKED(String, string, elements->get(i + 1));
7005 int length = string->length();
7006 if (is_ascii && !string->IsAsciiRepresentation()) {
7007 is_ascii = false;
7008 max_string_length = SeqTwoByteString::kMaxLength;
7009 }
7010 if (length > max_string_length ||
7011 max_string_length - length < string_length) {
7012 overflow = true;
7013 break;
7014 }
7015 string_length += length;
7016 }
7017 int separator_length = separator->length();
7018 if (!overflow && separator_length > 0) {
7019 if (array_length <= 0x7fffffffu) {
7020 int separator_count = static_cast<int>(array_length) - 1;
7021 int remaining_length = max_string_length - string_length;
7022 if ((remaining_length / separator_length) >= separator_count) {
7023 string_length += separator_length * (array_length - 1);
7024 } else {
7025 // Not room for the separators within the maximal string length.
7026 overflow = true;
7027 }
7028 } else {
7029 // Nonempty separator and at least 2^31-1 separators necessary
7030 // means that the string is too large to create.
7031 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7032 overflow = true;
7033 }
7034 }
7035 if (overflow) {
7036 // Throw OutOfMemory exception for creating too large a string.
7037 V8::FatalProcessOutOfMemory("Array join result too large.");
7038 }
7039
7040 if (is_ascii) {
7041 MaybeObject* result_allocation =
7042 isolate->heap()->AllocateRawAsciiString(string_length);
7043 if (result_allocation->IsFailure()) return result_allocation;
7044 SeqAsciiString* result_string =
7045 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7046 JoinSparseArrayWithSeparator<char>(elements,
7047 elements_length,
7048 array_length,
7049 separator,
7050 Vector<char>(result_string->GetChars(),
7051 string_length));
7052 return result_string;
7053 } else {
7054 MaybeObject* result_allocation =
7055 isolate->heap()->AllocateRawTwoByteString(string_length);
7056 if (result_allocation->IsFailure()) return result_allocation;
7057 SeqTwoByteString* result_string =
7058 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7059 JoinSparseArrayWithSeparator<uc16>(elements,
7060 elements_length,
7061 array_length,
7062 separator,
7063 Vector<uc16>(result_string->GetChars(),
7064 string_length));
7065 return result_string;
7066 }
7067}
7068
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087}
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7095 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097}
7098
7099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 1);
7103
7104 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
7113 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7114 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007115 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116}
7117
7118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120 NoHandleAllocation ha;
7121 ASSERT(args.length() == 2);
7122
7123 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7124 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126}
7127
7128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 2);
7132
7133 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7134 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007135 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136}
7137
7138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007139RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007140 NoHandleAllocation ha;
7141 ASSERT(args.length() == 2);
7142
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007143 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7144 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7146 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7147 if (x == y) return Smi::FromInt(EQUAL);
7148 Object* result;
7149 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7150 result = Smi::FromInt(EQUAL);
7151 } else {
7152 result = Smi::FromInt(NOT_EQUAL);
7153 }
7154 return result;
7155}
7156
7157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007158RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 NoHandleAllocation ha;
7160 ASSERT(args.length() == 2);
7161
7162 CONVERT_CHECKED(String, x, args[0]);
7163 CONVERT_CHECKED(String, y, args[1]);
7164
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007165 bool not_equal = !x->Equals(y);
7166 // This is slightly convoluted because the value that signifies
7167 // equality is 0 and inequality is 1 so we have to negate the result
7168 // from String::Equals.
7169 ASSERT(not_equal == 0 || not_equal == 1);
7170 STATIC_CHECK(EQUAL == 0);
7171 STATIC_CHECK(NOT_EQUAL == 1);
7172 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173}
7174
7175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007176RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 NoHandleAllocation ha;
7178 ASSERT(args.length() == 3);
7179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007180 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7181 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007182 if (isnan(x) || isnan(y)) return args[2];
7183 if (x == y) return Smi::FromInt(EQUAL);
7184 if (isless(x, y)) return Smi::FromInt(LESS);
7185 return Smi::FromInt(GREATER);
7186}
7187
7188
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007189// Compare two Smis as if they were converted to strings and then
7190// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007191RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 NoHandleAllocation ha;
7193 ASSERT(args.length() == 2);
7194
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007195 // Extract the integer values from the Smis.
7196 CONVERT_CHECKED(Smi, x, args[0]);
7197 CONVERT_CHECKED(Smi, y, args[1]);
7198 int x_value = x->value();
7199 int y_value = y->value();
7200
7201 // If the integers are equal so are the string representations.
7202 if (x_value == y_value) return Smi::FromInt(EQUAL);
7203
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007205 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007206 if (x_value == 0 || y_value == 0)
7207 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007208
ager@chromium.org32912102009-01-16 10:38:43 +00007209 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007210 // smallest because the char code of '-' is less than the char code
7211 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007212
7213 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7214 // architectures using 32-bit Smis.
7215 uint32_t x_scaled = x_value;
7216 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007217 if (x_value < 0 || y_value < 0) {
7218 if (y_value >= 0) return Smi::FromInt(LESS);
7219 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007220 x_scaled = -x_value;
7221 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007222 }
7223
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007224 static const uint32_t kPowersOf10[] = {
7225 1, 10, 100, 1000, 10*1000, 100*1000,
7226 1000*1000, 10*1000*1000, 100*1000*1000,
7227 1000*1000*1000
7228 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007229
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007230 // If the integers have the same number of decimal digits they can be
7231 // compared directly as the numeric order is the same as the
7232 // lexicographic order. If one integer has fewer digits, it is scaled
7233 // by some power of 10 to have the same number of digits as the longer
7234 // integer. If the scaled integers are equal it means the shorter
7235 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007236
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007237 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7238 int x_log2 = IntegerLog2(x_scaled);
7239 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7240 x_log10 -= x_scaled < kPowersOf10[x_log10];
7241
7242 int y_log2 = IntegerLog2(y_scaled);
7243 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7244 y_log10 -= y_scaled < kPowersOf10[y_log10];
7245
7246 int tie = EQUAL;
7247
7248 if (x_log10 < y_log10) {
7249 // X has fewer digits. We would like to simply scale up X but that
7250 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7251 // be scaled up to 9_000_000_000. So we scale up by the next
7252 // smallest power and scale down Y to drop one digit. It is OK to
7253 // drop one digit from the longer integer since the final digit is
7254 // past the length of the shorter integer.
7255 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7256 y_scaled /= 10;
7257 tie = LESS;
7258 } else if (y_log10 < x_log10) {
7259 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7260 x_scaled /= 10;
7261 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007262 }
7263
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007264 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7265 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7266 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007267}
7268
7269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007270static Object* StringInputBufferCompare(RuntimeState* state,
7271 String* x,
7272 String* y) {
7273 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7274 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007275 bufx.Reset(x);
7276 bufy.Reset(y);
7277 while (bufx.has_more() && bufy.has_more()) {
7278 int d = bufx.GetNext() - bufy.GetNext();
7279 if (d < 0) return Smi::FromInt(LESS);
7280 else if (d > 0) return Smi::FromInt(GREATER);
7281 }
7282
7283 // x is (non-trivial) prefix of y:
7284 if (bufy.has_more()) return Smi::FromInt(LESS);
7285 // y is prefix of x:
7286 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7287}
7288
7289
7290static Object* FlatStringCompare(String* x, String* y) {
7291 ASSERT(x->IsFlat());
7292 ASSERT(y->IsFlat());
7293 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7294 int prefix_length = x->length();
7295 if (y->length() < prefix_length) {
7296 prefix_length = y->length();
7297 equal_prefix_result = Smi::FromInt(GREATER);
7298 } else if (y->length() > prefix_length) {
7299 equal_prefix_result = Smi::FromInt(LESS);
7300 }
7301 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007302 String::FlatContent x_content = x->GetFlatContent();
7303 String::FlatContent y_content = y->GetFlatContent();
7304 if (x_content.IsAscii()) {
7305 Vector<const char> x_chars = x_content.ToAsciiVector();
7306 if (y_content.IsAscii()) {
7307 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007308 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007310 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007311 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7312 }
7313 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007314 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7315 if (y_content.IsAscii()) {
7316 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007317 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7318 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007319 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007320 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7321 }
7322 }
7323 Object* result;
7324 if (r == 0) {
7325 result = equal_prefix_result;
7326 } else {
7327 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 ASSERT(result ==
7330 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007331 return result;
7332}
7333
7334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007335RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336 NoHandleAllocation ha;
7337 ASSERT(args.length() == 2);
7338
7339 CONVERT_CHECKED(String, x, args[0]);
7340 CONVERT_CHECKED(String, y, args[1]);
7341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007342 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 // A few fast case tests before we flatten.
7345 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007346 if (y->length() == 0) {
7347 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007349 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 return Smi::FromInt(LESS);
7351 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007353 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007354 if (d < 0) return Smi::FromInt(LESS);
7355 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356
lrn@chromium.org303ada72010-10-27 09:33:13 +00007357 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007359 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7360 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007362 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007365 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
7389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391 NoHandleAllocation ha;
7392 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007395 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397}
7398
7399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007400static const double kPiDividedBy4 = 0.78539816339744830962;
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7409 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410 double result;
7411 if (isinf(x) && isinf(y)) {
7412 // Make sure that the result in case of two infinite arguments
7413 // is a multiple of Pi / 4. The sign of the result is determined
7414 // by the first argument (x) and the sign of the second argument
7415 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416 int multiplier = (x < 0) ? -1 : 1;
7417 if (y < 0) multiplier *= 3;
7418 result = multiplier * kPiDividedBy4;
7419 } else {
7420 result = atan2(x, y);
7421 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007422 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423}
7424
7425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433}
7434
7435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007436RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 NoHandleAllocation ha;
7438 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007442 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443}
7444
7445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007446RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 NoHandleAllocation ha;
7448 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007451 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007452 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453}
7454
7455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007461 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007462 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007463}
7464
7465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007466RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 NoHandleAllocation ha;
7468 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007471 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007472 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473}
7474
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007475// Slow version of Math.pow. We check for fast paths for special cases.
7476// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007483
7484 // If the second argument is a smi, it is much faster to call the
7485 // custom powi() function than the generic pow().
7486 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007487 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007489 }
7490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007491 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007492 int y_int = static_cast<int>(y);
7493 double result;
7494 if (y == y_int) {
7495 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7496 } else if (y == 0.5) {
7497 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7498 } else if (y == -0.5) {
7499 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7500 } else {
7501 result = power_double_double(x, y);
7502 }
7503 if (isnan(result)) return isolate->heap()->nan_value();
7504 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505}
7506
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007507// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007508// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007510 NoHandleAllocation ha;
7511 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007512 isolate->counters()->math_pow()->Increment();
7513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007514 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7515 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007517 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007518 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007519 double result = power_double_double(x, y);
7520 if (isnan(result)) return isolate->heap()->nan_value();
7521 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007522 }
7523}
7524
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007526RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007527 NoHandleAllocation ha;
7528 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007531 if (!args[0]->IsHeapNumber()) {
7532 // Must be smi. Return the argument unchanged for all the other types
7533 // to make fuzz-natives test happy.
7534 return args[0];
7535 }
7536
7537 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7538
7539 double value = number->value();
7540 int exponent = number->get_exponent();
7541 int sign = number->get_sign();
7542
danno@chromium.org160a7b02011-04-18 15:51:38 +00007543 if (exponent < -1) {
7544 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7545 if (sign) return isolate->heap()->minus_zero_value();
7546 return Smi::FromInt(0);
7547 }
7548
7549 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7550 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007551 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007552 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007553 return Smi::FromInt(static_cast<int>(value + 0.5));
7554 }
7555
7556 // If the magnitude is big enough, there's no place for fraction part. If we
7557 // try to add 0.5 to this number, 1.0 will be added instead.
7558 if (exponent >= 52) {
7559 return number;
7560 }
7561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007563
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007564 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566}
7567
7568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 NoHandleAllocation ha;
7571 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007574 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576}
7577
7578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007579RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580 NoHandleAllocation ha;
7581 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007585 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586}
7587
7588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007589RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007590 NoHandleAllocation ha;
7591 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007592 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007595 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596}
7597
7598
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007599static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007600 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7601 181, 212, 243, 273, 304, 334};
7602 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7603 182, 213, 244, 274, 305, 335};
7604
7605 year += month / 12;
7606 month %= 12;
7607 if (month < 0) {
7608 year--;
7609 month += 12;
7610 }
7611
7612 ASSERT(month >= 0);
7613 ASSERT(month < 12);
7614
7615 // year_delta is an arbitrary number such that:
7616 // a) year_delta = -1 (mod 400)
7617 // b) year + year_delta > 0 for years in the range defined by
7618 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7619 // Jan 1 1970. This is required so that we don't run into integer
7620 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007621 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007622 // operations.
7623 static const int year_delta = 399999;
7624 static const int base_day = 365 * (1970 + year_delta) +
7625 (1970 + year_delta) / 4 -
7626 (1970 + year_delta) / 100 +
7627 (1970 + year_delta) / 400;
7628
7629 int year1 = year + year_delta;
7630 int day_from_year = 365 * year1 +
7631 year1 / 4 -
7632 year1 / 100 +
7633 year1 / 400 -
7634 base_day;
7635
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007636 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7637 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007638 }
7639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007640 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007641}
7642
7643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007644RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007645 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007646 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007647
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007648 CONVERT_SMI_ARG_CHECKED(year, 0);
7649 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007650
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007651 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007652}
7653
7654
7655static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7656static const int kDaysIn4Years = 4 * 365 + 1;
7657static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7658static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7659static const int kDays1970to2000 = 30 * 365 + 7;
7660static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7661 kDays1970to2000;
7662static const int kYearsOffset = 400000;
7663
7664static const char kDayInYear[] = {
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7689
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30,
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7714
7715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7716 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7718 22, 23, 24, 25, 26, 27, 28, 29,
7719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7720 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7722 22, 23, 24, 25, 26, 27, 28, 29, 30,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7732 22, 23, 24, 25, 26, 27, 28, 29, 30,
7733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7734 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7736 22, 23, 24, 25, 26, 27, 28, 29, 30,
7737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7739
7740 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7741 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7743 22, 23, 24, 25, 26, 27, 28,
7744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7745 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7747 22, 23, 24, 25, 26, 27, 28, 29, 30,
7748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7749 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7751 22, 23, 24, 25, 26, 27, 28, 29, 30,
7752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7755 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7757 22, 23, 24, 25, 26, 27, 28, 29, 30,
7758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7759 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7761 22, 23, 24, 25, 26, 27, 28, 29, 30,
7762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7763 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7764
7765static const char kMonthInYear[] = {
7766 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,
7767 0, 0, 0, 0, 0, 0,
7768 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,
7769 1, 1, 1,
7770 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7771 2, 2, 2, 2, 2, 2,
7772 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7773 3, 3, 3, 3, 3,
7774 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7775 4, 4, 4, 4, 4, 4,
7776 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7777 5, 5, 5, 5, 5,
7778 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7779 6, 6, 6, 6, 6, 6,
7780 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7781 7, 7, 7, 7, 7, 7,
7782 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7783 8, 8, 8, 8, 8,
7784 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7785 9, 9, 9, 9, 9, 9,
7786 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7787 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7788 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7789 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7790
7791 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,
7792 0, 0, 0, 0, 0, 0,
7793 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,
7794 1, 1, 1,
7795 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7796 2, 2, 2, 2, 2, 2,
7797 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7798 3, 3, 3, 3, 3,
7799 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7800 4, 4, 4, 4, 4, 4,
7801 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7802 5, 5, 5, 5, 5,
7803 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7804 6, 6, 6, 6, 6, 6,
7805 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7806 7, 7, 7, 7, 7, 7,
7807 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7808 8, 8, 8, 8, 8,
7809 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7810 9, 9, 9, 9, 9, 9,
7811 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7812 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7813 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7814 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7815
7816 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,
7817 0, 0, 0, 0, 0, 0,
7818 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,
7819 1, 1, 1, 1,
7820 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7821 2, 2, 2, 2, 2, 2,
7822 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7823 3, 3, 3, 3, 3,
7824 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7825 4, 4, 4, 4, 4, 4,
7826 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7827 5, 5, 5, 5, 5,
7828 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7829 6, 6, 6, 6, 6, 6,
7830 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7831 7, 7, 7, 7, 7, 7,
7832 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7833 8, 8, 8, 8, 8,
7834 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7835 9, 9, 9, 9, 9, 9,
7836 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7837 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7838 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7839 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7840
7841 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,
7842 0, 0, 0, 0, 0, 0,
7843 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,
7844 1, 1, 1,
7845 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7846 2, 2, 2, 2, 2, 2,
7847 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7848 3, 3, 3, 3, 3,
7849 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7850 4, 4, 4, 4, 4, 4,
7851 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7852 5, 5, 5, 5, 5,
7853 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7854 6, 6, 6, 6, 6, 6,
7855 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7856 7, 7, 7, 7, 7, 7,
7857 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7858 8, 8, 8, 8, 8,
7859 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7860 9, 9, 9, 9, 9, 9,
7861 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7862 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7863 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7864 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7865
7866
7867// This function works for dates from 1970 to 2099.
7868static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007869 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007871 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007872#endif
7873
7874 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7875 date %= kDaysIn4Years;
7876
7877 month = kMonthInYear[date];
7878 day = kDayInYear[date];
7879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007880 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007881}
7882
7883
7884static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007885 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007887 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007888#endif
7889
7890 date += kDaysOffset;
7891 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7892 date %= kDaysIn400Years;
7893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007894 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007895
7896 date--;
7897 int yd1 = date / kDaysIn100Years;
7898 date %= kDaysIn100Years;
7899 year += 100 * yd1;
7900
7901 date++;
7902 int yd2 = date / kDaysIn4Years;
7903 date %= kDaysIn4Years;
7904 year += 4 * yd2;
7905
7906 date--;
7907 int yd3 = date / 365;
7908 date %= 365;
7909 year += yd3;
7910
7911 bool is_leap = (!yd1 || yd2) && !yd3;
7912
7913 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007914 ASSERT(is_leap || (date >= 0));
7915 ASSERT((date < 365) || (is_leap && (date < 366)));
7916 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007917 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7918 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007919
7920 if (is_leap) {
7921 day = kDayInYear[2*365 + 1 + date];
7922 month = kMonthInYear[2*365 + 1 + date];
7923 } else {
7924 day = kDayInYear[date];
7925 month = kMonthInYear[date];
7926 }
7927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007928 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007929}
7930
7931
7932static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007933 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007934 if (date >= 0 && date < 32 * kDaysIn4Years) {
7935 DateYMDFromTimeAfter1970(date, year, month, day);
7936 } else {
7937 DateYMDFromTimeSlow(date, year, month, day);
7938 }
7939}
7940
7941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007942RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007943 NoHandleAllocation ha;
7944 ASSERT(args.length() == 2);
7945
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007946 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007947 CONVERT_CHECKED(JSArray, res_array, args[1]);
7948
7949 int year, month, day;
7950 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7951
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007952 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7953 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007954 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007955
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007956 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7957 if (maybe->IsFailure()) return maybe;
7958 FixedArray* elms = FixedArray::cast(res_array->elements());
7959 elms->set(0, Smi::FromInt(year));
7960 elms->set(1, Smi::FromInt(month));
7961 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007963 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007964}
7965
7966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007967RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007968 HandleScope scope(isolate);
7969 ASSERT(args.length() == 3);
7970
7971 Handle<JSFunction> callee = args.at<JSFunction>(0);
7972 Object** parameters = reinterpret_cast<Object**>(args[1]);
7973 const int argument_count = Smi::cast(args[2])->value();
7974
7975 Handle<JSObject> result =
7976 isolate->factory()->NewArgumentsObject(callee, argument_count);
7977 // Allocate the elements if needed.
7978 int parameter_count = callee->shared()->formal_parameter_count();
7979 if (argument_count > 0) {
7980 if (parameter_count > 0) {
7981 int mapped_count = Min(argument_count, parameter_count);
7982 Handle<FixedArray> parameter_map =
7983 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7984 parameter_map->set_map(
7985 isolate->heap()->non_strict_arguments_elements_map());
7986
7987 Handle<Map> old_map(result->map());
7988 Handle<Map> new_map =
7989 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007990 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007991
7992 result->set_map(*new_map);
7993 result->set_elements(*parameter_map);
7994
7995 // Store the context and the arguments array at the beginning of the
7996 // parameter map.
7997 Handle<Context> context(isolate->context());
7998 Handle<FixedArray> arguments =
7999 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8000 parameter_map->set(0, *context);
8001 parameter_map->set(1, *arguments);
8002
8003 // Loop over the actual parameters backwards.
8004 int index = argument_count - 1;
8005 while (index >= mapped_count) {
8006 // These go directly in the arguments array and have no
8007 // corresponding slot in the parameter map.
8008 arguments->set(index, *(parameters - index - 1));
8009 --index;
8010 }
8011
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008012 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008013 while (index >= 0) {
8014 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008015 Handle<String> name(scope_info->ParameterName(index));
8016 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008017 bool duplicate = false;
8018 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008019 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008020 duplicate = true;
8021 break;
8022 }
8023 }
8024
8025 if (duplicate) {
8026 // This goes directly in the arguments array with a hole in the
8027 // parameter map.
8028 arguments->set(index, *(parameters - index - 1));
8029 parameter_map->set_the_hole(index + 2);
8030 } else {
8031 // The context index goes in the parameter map with a hole in the
8032 // arguments array.
8033 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008034 for (int j = 0; j < context_local_count; ++j) {
8035 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 context_index = j;
8037 break;
8038 }
8039 }
8040 ASSERT(context_index >= 0);
8041 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008042 parameter_map->set(index + 2, Smi::FromInt(
8043 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008044 }
8045
8046 --index;
8047 }
8048 } else {
8049 // If there is no aliasing, the arguments object elements are not
8050 // special in any way.
8051 Handle<FixedArray> elements =
8052 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8053 result->set_elements(*elements);
8054 for (int i = 0; i < argument_count; ++i) {
8055 elements->set(i, *(parameters - i - 1));
8056 }
8057 }
8058 }
8059 return *result;
8060}
8061
8062
8063RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008064 NoHandleAllocation ha;
8065 ASSERT(args.length() == 3);
8066
8067 JSFunction* callee = JSFunction::cast(args[0]);
8068 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008069 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008070
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 { MaybeObject* maybe_result =
8073 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008074 if (!maybe_result->ToObject(&result)) return maybe_result;
8075 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008076 // Allocate the elements if needed.
8077 if (length > 0) {
8078 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008079 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008080 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008081 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8082 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008083
8084 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008085 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008086 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008087 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008088
8089 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008090 for (int i = 0; i < length; i++) {
8091 array->set(i, *--parameters, mode);
8092 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008093 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008094 }
8095 return result;
8096}
8097
8098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008099RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008101 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008102 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008103 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008104 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105
whesse@chromium.org7b260152011-06-20 15:33:18 +00008106 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008107 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008108 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008109 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008110 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8111 context,
8112 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113 return *result;
8114}
8115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008116
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117// Find the arguments of the JavaScript function invocation that called
8118// into C++ code. Collect these in a newly allocated array of handles (possibly
8119// prefixed by a number of empty handles).
8120static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8121 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008122 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008123 // Find frame containing arguments passed to the caller.
8124 JavaScriptFrameIterator it;
8125 JavaScriptFrame* frame = it.frame();
8126 List<JSFunction*> functions(2);
8127 frame->GetFunctions(&functions);
8128 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008129 int inlined_jsframe_index = functions.length() - 1;
8130 JSFunction* inlined_function = functions[inlined_jsframe_index];
8131 Vector<SlotRef> args_slots =
8132 SlotRef::ComputeSlotMappingForArguments(
8133 frame,
8134 inlined_jsframe_index,
8135 inlined_function->shared()->formal_parameter_count());
8136
8137 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008138
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008139 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008140 SmartArrayPointer<Handle<Object> > param_data(
8141 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008142 for (int i = 0; i < args_count; i++) {
8143 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008144 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008145 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008146
8147 args_slots.Dispose();
8148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008149 return param_data;
8150 } else {
8151 it.AdvanceToArgumentsFrame();
8152 frame = it.frame();
8153 int args_count = frame->ComputeParametersCount();
8154
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008155 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008156 SmartArrayPointer<Handle<Object> > param_data(
8157 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008158 for (int i = 0; i < args_count; i++) {
8159 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008160 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008161 }
8162 return param_data;
8163 }
8164}
8165
8166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008167RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8168 HandleScope scope(isolate);
8169 ASSERT(args.length() == 4);
8170 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8171 RUNTIME_ASSERT(args[3]->IsNumber());
8172 Handle<Object> bindee = args.at<Object>(1);
8173
8174 // TODO(lrn): Create bound function in C++ code from premade shared info.
8175 bound_function->shared()->set_bound(true);
8176 // Get all arguments of calling function (Function.prototype.bind).
8177 int argc = 0;
8178 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8179 // Don't count the this-arg.
8180 if (argc > 0) {
8181 ASSERT(*arguments[0] == args[2]);
8182 argc--;
8183 } else {
8184 ASSERT(args[2]->IsUndefined());
8185 }
8186 // Initialize array of bindings (function, this, and any existing arguments
8187 // if the function was already bound).
8188 Handle<FixedArray> new_bindings;
8189 int i;
8190 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8191 Handle<FixedArray> old_bindings(
8192 JSFunction::cast(*bindee)->function_bindings());
8193 new_bindings =
8194 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8195 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8196 i = 0;
8197 for (int n = old_bindings->length(); i < n; i++) {
8198 new_bindings->set(i, old_bindings->get(i));
8199 }
8200 } else {
8201 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8202 new_bindings = isolate->factory()->NewFixedArray(array_size);
8203 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8204 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8205 i = 2;
8206 }
8207 // Copy arguments, skipping the first which is "this_arg".
8208 for (int j = 0; j < argc; j++, i++) {
8209 new_bindings->set(i, *arguments[j + 1]);
8210 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008211 new_bindings->set_map_no_write_barrier(
8212 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008213 bound_function->set_function_bindings(*new_bindings);
8214
8215 // Update length.
8216 Handle<String> length_symbol = isolate->factory()->length_symbol();
8217 Handle<Object> new_length(args.at<Object>(3));
8218 PropertyAttributes attr =
8219 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8220 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8221 return *bound_function;
8222}
8223
8224
8225RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8226 HandleScope handles(isolate);
8227 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008228 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008229 if (callable->IsJSFunction()) {
8230 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8231 if (function->shared()->bound()) {
8232 Handle<FixedArray> bindings(function->function_bindings());
8233 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8234 return *isolate->factory()->NewJSArrayWithElements(bindings);
8235 }
8236 }
8237 return isolate->heap()->undefined_value();
8238}
8239
8240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008241RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008243 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008244 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008245 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008246 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008247
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008248 // The argument is a bound function. Extract its bound arguments
8249 // and callable.
8250 Handle<FixedArray> bound_args =
8251 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8252 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8253 Handle<Object> bound_function(
8254 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8255 ASSERT(!bound_function->IsJSFunction() ||
8256 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008258 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008259 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008260 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008261 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008262 param_data[i] = Handle<Object>(bound_args->get(
8263 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008264 }
8265
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008266 if (!bound_function->IsJSFunction()) {
8267 bool exception_thrown;
8268 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8269 &exception_thrown);
8270 if (exception_thrown) return Failure::Exception();
8271 }
8272 ASSERT(bound_function->IsJSFunction());
8273
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008274 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008275 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008276 Execution::New(Handle<JSFunction>::cast(bound_function),
8277 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008278 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008279 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008280 }
8281 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008282 return *result;
8283}
8284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286static void TrySettingInlineConstructStub(Isolate* isolate,
8287 Handle<JSFunction> function) {
8288 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008289 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008291 }
8292 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008293 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008294 Handle<Code> code = compiler.CompileConstructStub(function);
8295 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008296 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008297}
8298
8299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008300RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008301 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008302 ASSERT(args.length() == 1);
8303
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008304 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008306 // If the constructor isn't a proper function we throw a type error.
8307 if (!constructor->IsJSFunction()) {
8308 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8309 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 isolate->factory()->NewTypeError("not_constructor", arguments);
8311 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008312 }
8313
8314 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008315
8316 // If function should not have prototype, construction is not allowed. In this
8317 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008318 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008319 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8320 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008321 isolate->factory()->NewTypeError("not_constructor", arguments);
8322 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008323 }
8324
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008325#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008327 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008328 if (debug->StepInActive()) {
8329 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008330 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008331#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008333 if (function->has_initial_map()) {
8334 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 // The 'Function' function ignores the receiver object when
8336 // called using 'new' and creates a new JSFunction object that
8337 // is returned. The receiver object is only used for error
8338 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008339 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008340 // allocate JSFunctions since it does not properly initialize
8341 // the shared part of the function. Since the receiver is
8342 // ignored anyway, we use the global object as the receiver
8343 // instead of a new JSFunction object. This way, errors are
8344 // reported the same way whether or not 'Function' is called
8345 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008346 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008348 }
8349
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008350 // The function should be compiled for the optimization hints to be
8351 // available. We cannot use EnsureCompiled because that forces a
8352 // compilation through the shared function info which makes it
8353 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008354 if (!function->is_compiled()) {
8355 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8356 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008357
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008358 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008359 if (!function->has_initial_map() &&
8360 shared->IsInobjectSlackTrackingInProgress()) {
8361 // The tracking is already in progress for another function. We can only
8362 // track one initial_map at a time, so we force the completion before the
8363 // function is called as a constructor for the first time.
8364 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008365 }
8366
8367 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8369 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008370 // Delay setting the stub if inobject slack tracking is in progress.
8371 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008372 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008373 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 isolate->counters()->constructed_objects()->Increment();
8376 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008377
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008378 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008379}
8380
8381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008382RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008383 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008384 ASSERT(args.length() == 1);
8385
8386 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8387 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008388 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008389
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008391}
8392
8393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008394RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008395 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008396 ASSERT(args.length() == 1);
8397
8398 Handle<JSFunction> function = args.at<JSFunction>(0);
8399#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008400 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008402 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008403 PrintF("]\n");
8404 }
8405#endif
8406
lrn@chromium.org34e60782011-09-15 07:25:40 +00008407 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008409 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 return Failure::Exception();
8411 }
8412
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008413 // All done. Return the compiled code.
8414 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415 return function->code();
8416}
8417
8418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008419RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008421 ASSERT(args.length() == 1);
8422 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008423
8424 // If the function is not compiled ignore the lazy
8425 // recompilation. This can happen if the debugger is activated and
8426 // the function is returned to the not compiled state.
8427 if (!function->shared()->is_compiled()) {
8428 function->ReplaceCode(function->shared()->code());
8429 return function->code();
8430 }
8431
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 // If the function is not optimizable or debugger is active continue using the
8433 // code from the full compiler.
8434 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008435 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008436 if (FLAG_trace_opt) {
8437 PrintF("[failed to optimize ");
8438 function->PrintName();
8439 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8440 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008441 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008442 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008443 function->ReplaceCode(function->shared()->code());
8444 return function->code();
8445 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008446 if (JSFunction::CompileOptimized(function,
8447 AstNode::kNoNumber,
8448 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 return function->code();
8450 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008451 if (FLAG_trace_opt) {
8452 PrintF("[failed to optimize ");
8453 function->PrintName();
8454 PrintF(": optimized compilation failed]\n");
8455 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008457 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008458}
8459
8460
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008461class ActivationsFinder : public ThreadVisitor {
8462 public:
8463 explicit ActivationsFinder(JSFunction* function)
8464 : function_(function), has_activations_(false) {}
8465
8466 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8467 if (has_activations_) return;
8468
8469 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8470 JavaScriptFrame* frame = it.frame();
8471 if (frame->is_optimized() && frame->function() == function_) {
8472 has_activations_ = true;
8473 return;
8474 }
8475 }
8476 }
8477
8478 bool has_activations() { return has_activations_; }
8479
8480 private:
8481 JSFunction* function_;
8482 bool has_activations_;
8483};
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488 ASSERT(args.length() == 1);
8489 RUNTIME_ASSERT(args[0]->IsSmi());
8490 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008491 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8493 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008494 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008496 deoptimizer->MaterializeHeapNumbers();
8497 delete deoptimizer;
8498
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008499 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008501 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008502 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008503
8504 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008505 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008506 Handle<Object> arguments;
8507 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008509 if (arguments.is_null()) {
8510 // FunctionGetArguments can't throw an exception, so cast away the
8511 // doubt with an assert.
8512 arguments = Handle<Object>(
8513 Accessors::FunctionGetArguments(*function,
8514 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 ASSERT(*arguments != isolate->heap()->null_value());
8516 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008517 }
8518 frame->SetExpression(i, *arguments);
8519 }
8520 }
8521
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008522 if (type == Deoptimizer::EAGER) {
8523 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008524 }
8525
8526 // Avoid doing too much work when running with --always-opt and keep
8527 // the optimized code around.
8528 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008529 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008530 }
8531
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008532 // Find other optimized activations of the function.
8533 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008534 while (!it.done()) {
8535 JavaScriptFrame* frame = it.frame();
8536 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008537 has_other_activations = true;
8538 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008539 }
8540 it.Advance();
8541 }
8542
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008543 if (!has_other_activations) {
8544 ActivationsFinder activations_finder(*function);
8545 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8546 has_other_activations = activations_finder.has_activations();
8547 }
8548
8549 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008550 if (FLAG_trace_deopt) {
8551 PrintF("[removing optimized code for: ");
8552 function->PrintName();
8553 PrintF("]\n");
8554 }
8555 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008556 } else {
8557 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560}
8561
8562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008563RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008565 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008567}
8568
8569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008570RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008572 ASSERT(args.length() == 1);
8573 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008574 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008575
8576 Deoptimizer::DeoptimizeFunction(*function);
8577
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008579}
8580
8581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8583#if defined(USE_SIMULATOR)
8584 return isolate->heap()->true_value();
8585#else
8586 return isolate->heap()->false_value();
8587#endif
8588}
8589
8590
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008591RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8592 HandleScope scope(isolate);
8593 ASSERT(args.length() == 1);
8594 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8595 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8596 function->MarkForLazyRecompilation();
8597 return isolate->heap()->undefined_value();
8598}
8599
8600
lrn@chromium.org1c092762011-05-09 09:42:16 +00008601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8602 HandleScope scope(isolate);
8603 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008604 // The least significant bit (after untagging) indicates whether the
8605 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008606 if (!V8::UseCrankshaft()) {
8607 return Smi::FromInt(4); // 4 == "never".
8608 }
8609 if (FLAG_always_opt) {
8610 return Smi::FromInt(3); // 3 == "always".
8611 }
8612 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8613 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8614 : Smi::FromInt(2); // 2 == "no".
8615}
8616
8617
8618RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8619 HandleScope scope(isolate);
8620 ASSERT(args.length() == 1);
8621 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8622 return Smi::FromInt(function->shared()->opt_count());
8623}
8624
8625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008626RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008627 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628 ASSERT(args.length() == 1);
8629 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8630
8631 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008632 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008633
8634 // We have hit a back edge in an unoptimized frame for a function that was
8635 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008636 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008637 // Keep track of whether we've succeeded in optimizing.
8638 bool succeeded = unoptimized->optimizable();
8639 if (succeeded) {
8640 // If we are trying to do OSR when there are already optimized
8641 // activations of the function, it means (a) the function is directly or
8642 // indirectly recursive and (b) an optimized invocation has been
8643 // deoptimized so that we are currently in an unoptimized activation.
8644 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008645 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646 while (succeeded && !it.done()) {
8647 JavaScriptFrame* frame = it.frame();
8648 succeeded = !frame->is_optimized() || frame->function() != *function;
8649 it.Advance();
8650 }
8651 }
8652
8653 int ast_id = AstNode::kNoNumber;
8654 if (succeeded) {
8655 // The top JS function is this one, the PC is somewhere in the
8656 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008657 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008658 JavaScriptFrame* frame = it.frame();
8659 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008660 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008661 ASSERT(unoptimized->contains(frame->pc()));
8662
8663 // Use linear search of the unoptimized code's stack check table to find
8664 // the AST id matching the PC.
8665 Address start = unoptimized->instruction_start();
8666 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008667 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008668 uint32_t table_length = Memory::uint32_at(table_cursor);
8669 table_cursor += kIntSize;
8670 for (unsigned i = 0; i < table_length; ++i) {
8671 // Table entries are (AST id, pc offset) pairs.
8672 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8673 if (pc_offset == target_pc_offset) {
8674 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8675 break;
8676 }
8677 table_cursor += 2 * kIntSize;
8678 }
8679 ASSERT(ast_id != AstNode::kNoNumber);
8680 if (FLAG_trace_osr) {
8681 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8682 function->PrintName();
8683 PrintF("]\n");
8684 }
8685
8686 // Try to compile the optimized code. A true return value from
8687 // CompileOptimized means that compilation succeeded, not necessarily
8688 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008689 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008690 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008691 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8692 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008693 if (data->OsrPcOffset()->value() >= 0) {
8694 if (FLAG_trace_osr) {
8695 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008696 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008697 }
8698 ASSERT(data->OsrAstId()->value() == ast_id);
8699 } else {
8700 // We may never generate the desired OSR entry if we emit an
8701 // early deoptimize.
8702 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008703 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008704 } else {
8705 succeeded = false;
8706 }
8707 }
8708
8709 // Revert to the original stack checks in the original unoptimized code.
8710 if (FLAG_trace_osr) {
8711 PrintF("[restoring original stack checks in ");
8712 function->PrintName();
8713 PrintF("]\n");
8714 }
8715 StackCheckStub check_stub;
8716 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008717 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008718 Deoptimizer::RevertStackCheckCode(*unoptimized,
8719 *check_code,
8720 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008721
8722 // Allow OSR only at nesting level zero again.
8723 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8724
8725 // If the optimization attempt succeeded, return the AST id tagged as a
8726 // smi. This tells the builtin that we need to translate the unoptimized
8727 // frame to an optimized one.
8728 if (succeeded) {
8729 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8730 return Smi::FromInt(ast_id);
8731 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008732 if (function->IsMarkedForLazyRecompilation()) {
8733 function->ReplaceCode(function->shared()->code());
8734 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008735 return Smi::FromInt(-1);
8736 }
8737}
8738
8739
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008740RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8741 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8742 return isolate->heap()->undefined_value();
8743}
8744
8745
danno@chromium.orgc612e022011-11-10 11:38:15 +00008746RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8747 HandleScope scope(isolate);
8748 ASSERT(args.length() >= 2);
8749 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8750 Object* receiver = args[0];
8751 int argc = args.length() - 2;
8752
8753 // If there are too many arguments, allocate argv via malloc.
8754 const int argv_small_size = 10;
8755 Handle<Object> argv_small_buffer[argv_small_size];
8756 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8757 Handle<Object>* argv = argv_small_buffer;
8758 if (argc > argv_small_size) {
8759 argv = new Handle<Object>[argc];
8760 if (argv == NULL) return isolate->StackOverflow();
8761 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8762 }
8763
8764 for (int i = 0; i < argc; ++i) {
8765 MaybeObject* maybe = args[1 + i];
8766 Object* object;
8767 if (!maybe->To<Object>(&object)) return maybe;
8768 argv[i] = Handle<Object>(object);
8769 }
8770
8771 bool threw;
8772 Handle<JSReceiver> hfun(fun);
8773 Handle<Object> hreceiver(receiver);
8774 Handle<Object> result =
8775 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8776
8777 if (threw) return Failure::Exception();
8778 return *result;
8779}
8780
8781
lrn@chromium.org34e60782011-09-15 07:25:40 +00008782RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8783 HandleScope scope(isolate);
8784 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008785 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8786 Handle<Object> receiver = args.at<Object>(1);
8787 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8788 CONVERT_SMI_ARG_CHECKED(offset, 3);
8789 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008790 ASSERT(offset >= 0);
8791 ASSERT(argc >= 0);
8792
8793 // If there are too many arguments, allocate argv via malloc.
8794 const int argv_small_size = 10;
8795 Handle<Object> argv_small_buffer[argv_small_size];
8796 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8797 Handle<Object>* argv = argv_small_buffer;
8798 if (argc > argv_small_size) {
8799 argv = new Handle<Object>[argc];
8800 if (argv == NULL) return isolate->StackOverflow();
8801 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8802 }
8803
8804 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008805 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008806 }
8807
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008808 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008809 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008810 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008811
8812 if (threw) return Failure::Exception();
8813 return *result;
8814}
8815
8816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008817RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819 ASSERT(args.length() == 1);
8820 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8821 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8822}
8823
8824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008826 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008827 ASSERT(args.length() == 1);
8828 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8829 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8830}
8831
8832
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008834 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008835 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836
kasper.lund7276f142008-07-30 08:49:36 +00008837 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008838 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008839 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008840 { MaybeObject* maybe_result =
8841 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008842 if (!maybe_result->ToObject(&result)) return maybe_result;
8843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008845 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846
kasper.lund7276f142008-07-30 08:49:36 +00008847 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848}
8849
lrn@chromium.org303ada72010-10-27 09:33:13 +00008850
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008851RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8852 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008853 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008854 JSObject* extension_object;
8855 if (args[0]->IsJSObject()) {
8856 extension_object = JSObject::cast(args[0]);
8857 } else {
8858 // Convert the object to a proper JavaScript object.
8859 MaybeObject* maybe_js_object = args[0]->ToObject();
8860 if (!maybe_js_object->To(&extension_object)) {
8861 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8862 HandleScope scope(isolate);
8863 Handle<Object> handle = args.at<Object>(0);
8864 Handle<Object> result =
8865 isolate->factory()->NewTypeError("with_expression",
8866 HandleVector(&handle, 1));
8867 return isolate->Throw(*result);
8868 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008869 return maybe_js_object;
8870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 }
8872 }
8873
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008874 JSFunction* function;
8875 if (args[1]->IsSmi()) {
8876 // A smi sentinel indicates a context nested inside global code rather
8877 // than some function. There is a canonical empty function that can be
8878 // gotten from the global context.
8879 function = isolate->context()->global_context()->closure();
8880 } else {
8881 function = JSFunction::cast(args[1]);
8882 }
8883
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008884 Context* context;
8885 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008886 isolate->heap()->AllocateWithContext(function,
8887 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008888 extension_object);
8889 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008891 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008892}
8893
8894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008895RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008896 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008897 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008898 String* name = String::cast(args[0]);
8899 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008900 JSFunction* function;
8901 if (args[2]->IsSmi()) {
8902 // A smi sentinel indicates a context nested inside global code rather
8903 // than some function. There is a canonical empty function that can be
8904 // gotten from the global context.
8905 function = isolate->context()->global_context()->closure();
8906 } else {
8907 function = JSFunction::cast(args[2]);
8908 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008909 Context* context;
8910 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008911 isolate->heap()->AllocateCatchContext(function,
8912 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008913 name,
8914 thrown_object);
8915 if (!maybe_context->To(&context)) return maybe_context;
8916 isolate->set_context(context);
8917 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008918}
8919
8920
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008921RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8922 NoHandleAllocation ha;
8923 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008924 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008925 JSFunction* function;
8926 if (args[1]->IsSmi()) {
8927 // A smi sentinel indicates a context nested inside global code rather
8928 // than some function. There is a canonical empty function that can be
8929 // gotten from the global context.
8930 function = isolate->context()->global_context()->closure();
8931 } else {
8932 function = JSFunction::cast(args[1]);
8933 }
8934 Context* context;
8935 MaybeObject* maybe_context =
8936 isolate->heap()->AllocateBlockContext(function,
8937 isolate->context(),
8938 scope_info);
8939 if (!maybe_context->To(&context)) return maybe_context;
8940 isolate->set_context(context);
8941 return context;
8942}
8943
8944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008945RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008946 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947 ASSERT(args.length() == 2);
8948
8949 CONVERT_ARG_CHECKED(Context, context, 0);
8950 CONVERT_ARG_CHECKED(String, name, 1);
8951
8952 int index;
8953 PropertyAttributes attributes;
8954 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008955 BindingFlags binding_flags;
8956 Handle<Object> holder = context->Lookup(name,
8957 flags,
8958 &index,
8959 &attributes,
8960 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008962 // If the slot was not found the result is true.
8963 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 }
8966
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008967 // If the slot was found in a context, it should be DONT_DELETE.
8968 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008970 }
8971
8972 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008973 // the global object, or the subject of a with. Try to delete it
8974 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008975 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008976 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977}
8978
8979
ager@chromium.orga1645e22009-09-09 19:27:10 +00008980// A mechanism to return a pair of Object pointers in registers (if possible).
8981// How this is achieved is calling convention-dependent.
8982// All currently supported x86 compiles uses calling conventions that are cdecl
8983// variants where a 64-bit value is returned in two 32-bit registers
8984// (edx:eax on ia32, r1:r0 on ARM).
8985// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8986// In Win64 calling convention, a struct of two pointers is returned in memory,
8987// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008988#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008989struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008990 MaybeObject* x;
8991 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008992};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008993
lrn@chromium.org303ada72010-10-27 09:33:13 +00008994static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008995 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008996 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8997 // In Win64 they are assigned to a hidden first argument.
8998 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008999}
9000#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009001typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009002static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009003 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009004 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009006#endif
9007
9008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009static inline MaybeObject* Unhole(Heap* heap,
9010 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009011 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9013 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009014 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015}
9016
9017
danno@chromium.org40cb8782011-05-25 07:58:50 +00009018static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9019 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009020 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009021 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009022 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009023 JSFunction* context_extension_function =
9024 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009025 // If the holder isn't a context extension object, we just return it
9026 // as the receiver. This allows arguments objects to be used as
9027 // receivers, but only if they are put in the context scope chain
9028 // explicitly via a with-statement.
9029 Object* constructor = holder->map()->constructor();
9030 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009031 // Fall back to using the global object as the implicit receiver if
9032 // the property turns out to be a local variable allocated in a
9033 // context extension object - introduced via eval. Implicit global
9034 // receivers are indicated with the hole value.
9035 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009036}
9037
9038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039static ObjectPair LoadContextSlotHelper(Arguments args,
9040 Isolate* isolate,
9041 bool throw_error) {
9042 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009043 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009045 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009047 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009049 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050
9051 int index;
9052 PropertyAttributes attributes;
9053 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009054 BindingFlags binding_flags;
9055 Handle<Object> holder = context->Lookup(name,
9056 flags,
9057 &index,
9058 &attributes,
9059 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009061 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009063 ASSERT(holder->IsContext());
9064 // If the "property" we were looking for is a local variable, the
9065 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009066 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009067 // Use the hole as the receiver to signal that the receiver is implicit
9068 // and that the global receiver should be used (as distinguished from an
9069 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009070 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009071 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009072 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009073 switch (binding_flags) {
9074 case MUTABLE_CHECK_INITIALIZED:
9075 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9076 if (value->IsTheHole()) {
9077 Handle<Object> reference_error =
9078 isolate->factory()->NewReferenceError("not_defined",
9079 HandleVector(&name, 1));
9080 return MakePair(isolate->Throw(*reference_error), NULL);
9081 }
9082 // FALLTHROUGH
9083 case MUTABLE_IS_INITIALIZED:
9084 case IMMUTABLE_IS_INITIALIZED:
9085 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9086 ASSERT(!value->IsTheHole());
9087 return MakePair(value, *receiver);
9088 case IMMUTABLE_CHECK_INITIALIZED:
9089 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9090 case MISSING_BINDING:
9091 UNREACHABLE();
9092 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094 }
9095
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009096 // Otherwise, if the slot was found the holder is a context extension
9097 // object, subject of a with, or a global object. We read the named
9098 // property from it.
9099 if (!holder.is_null()) {
9100 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9101 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009102 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009103 Handle<Object> receiver_handle(object->IsGlobalObject()
9104 ? GlobalObject::cast(*object)->global_receiver()
9105 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009106
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009107 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009108 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009109 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009110 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 }
9112
9113 if (throw_error) {
9114 // The property doesn't exist - throw exception.
9115 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 isolate->factory()->NewReferenceError("not_defined",
9117 HandleVector(&name, 1));
9118 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009120 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009121 return MakePair(isolate->heap()->undefined_value(),
9122 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 }
9124}
9125
9126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009127RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009128 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129}
9130
9131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009132RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009134}
9135
9136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009137RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009139 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009143 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009144 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9145 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9146 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147
9148 int index;
9149 PropertyAttributes attributes;
9150 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009151 BindingFlags binding_flags;
9152 Handle<Object> holder = context->Lookup(name,
9153 flags,
9154 &index,
9155 &attributes,
9156 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157
9158 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009159 // The property was found in a context slot.
9160 Handle<Context> context = Handle<Context>::cast(holder);
9161 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9162 context->get(index)->IsTheHole()) {
9163 Handle<Object> error =
9164 isolate->factory()->NewReferenceError("not_defined",
9165 HandleVector(&name, 1));
9166 return isolate->Throw(*error);
9167 }
9168 // Ignore if read_only variable.
9169 if ((attributes & READ_ONLY) == 0) {
9170 // Context is a fixed array and set cannot fail.
9171 context->set(index, *value);
9172 } else if (strict_mode == kStrictMode) {
9173 // Setting read only property in strict mode.
9174 Handle<Object> error =
9175 isolate->factory()->NewTypeError("strict_cannot_assign",
9176 HandleVector(&name, 1));
9177 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178 }
9179 return *value;
9180 }
9181
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009182 // Slow case: The property is not in a context slot. It is either in a
9183 // context extension object, a property of the subject of a with, or a
9184 // property of the global object.
9185 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009187 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009188 // The property exists on the holder.
9189 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009191 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009193
9194 if (strict_mode == kStrictMode) {
9195 // Throw in strict mode (assignment to undefined variable).
9196 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009197 isolate->factory()->NewReferenceError(
9198 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009199 return isolate->Throw(*error);
9200 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009201 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009203 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 }
9205
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009206 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009207 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009208 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009209 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009211 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009212 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009213 // Setting read only property in strict mode.
9214 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 isolate->factory()->NewTypeError(
9216 "strict_cannot_assign", HandleVector(&name, 1));
9217 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 }
9219 return *value;
9220}
9221
9222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009223RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225 ASSERT(args.length() == 1);
9226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228}
9229
9230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009231RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009232 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009233 ASSERT(args.length() == 1);
9234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009235 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236}
9237
9238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009239RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009240 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009242}
9243
9244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009245RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247 ASSERT(args.length() == 1);
9248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009249 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 isolate->factory()->NewReferenceError("not_defined",
9252 HandleVector(&name, 1));
9253 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254}
9255
9256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009257RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259
9260 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 if (isolate->stack_guard()->IsStackOverflow()) {
9262 NoHandleAllocation na;
9263 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009264 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009266 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009267}
9268
9269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270static int StackSize() {
9271 int n = 0;
9272 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9273 return n;
9274}
9275
9276
9277static void PrintTransition(Object* result) {
9278 // indentation
9279 { const int nmax = 80;
9280 int n = StackSize();
9281 if (n <= nmax)
9282 PrintF("%4d:%*s", n, n, "");
9283 else
9284 PrintF("%4d:%*s", n, nmax, "...");
9285 }
9286
9287 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009288 JavaScriptFrame::PrintTop(stdout, true, false);
9289 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 } else {
9291 // function result
9292 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009293 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294 PrintF("\n");
9295 }
9296}
9297
9298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009299RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009300 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301 NoHandleAllocation ha;
9302 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304}
9305
9306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009307RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 NoHandleAllocation ha;
9309 PrintTransition(args[0]);
9310 return args[0]; // return TOS
9311}
9312
9313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 NoHandleAllocation ha;
9316 ASSERT(args.length() == 1);
9317
9318#ifdef DEBUG
9319 if (args[0]->IsString()) {
9320 // If we have a string, assume it's a code "marker"
9321 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009322 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009324 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9325 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009326 } else {
9327 PrintF("DebugPrint: ");
9328 }
9329 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009330 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009331 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009332 HeapObject::cast(args[0])->map()->Print();
9333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009335 // ShortPrint is available in release mode. Print is not.
9336 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337#endif
9338 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009339 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340
9341 return args[0]; // return TOS
9342}
9343
9344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009345RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009346 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009348 isolate->PrintStack();
9349 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350}
9351
9352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009353RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009355 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356
9357 // According to ECMA-262, section 15.9.1, page 117, the precision of
9358 // the number in a Date object representing a particular instant in
9359 // time is milliseconds. Therefore, we floor the result of getting
9360 // the OS time.
9361 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363}
9364
9365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009366RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009368 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009370 CONVERT_ARG_CHECKED(String, str, 0);
9371 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009373 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009374
9375 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009376 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009377 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009378 RUNTIME_ASSERT(output->HasFastElements());
9379
9380 AssertNoAllocation no_allocation;
9381
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009382 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009383 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9384 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009385 String::FlatContent str_content = str->GetFlatContent();
9386 if (str_content.IsAscii()) {
9387 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009388 output_array,
9389 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009391 ASSERT(str_content.IsTwoByte());
9392 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009393 output_array,
9394 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009395 }
9396
9397 if (result) {
9398 return *output;
9399 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009400 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 }
9402}
9403
9404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009405RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 NoHandleAllocation ha;
9407 ASSERT(args.length() == 1);
9408
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009409 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009410 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412}
9413
9414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009415RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009417 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009420}
9421
9422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009423RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424 NoHandleAllocation ha;
9425 ASSERT(args.length() == 1);
9426
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009427 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009429}
9430
9431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009432RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009433 ASSERT(args.length() == 1);
9434 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009435 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009436 return JSGlobalObject::cast(global)->global_receiver();
9437}
9438
9439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009440RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009441 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009442 ASSERT_EQ(1, args.length());
9443 CONVERT_ARG_CHECKED(String, source, 0);
9444
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009445 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009446 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009447 Handle<Object> result;
9448 if (source->IsSeqAsciiString()) {
9449 result = JsonParser<true>::Parse(source);
9450 } else {
9451 result = JsonParser<false>::Parse(source);
9452 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009453 if (result.is_null()) {
9454 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009455 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009456 return Failure::Exception();
9457 }
9458 return *result;
9459}
9460
9461
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009462bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9463 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009464 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9465 // Check with callback if set.
9466 AllowCodeGenerationFromStringsCallback callback =
9467 isolate->allow_code_gen_callback();
9468 if (callback == NULL) {
9469 // No callback set and code generation disallowed.
9470 return false;
9471 } else {
9472 // Callback set. Let it decide if code generation is allowed.
9473 VMState state(isolate, EXTERNAL);
9474 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009475 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009476}
9477
9478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009479RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009481 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009482 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009483
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009484 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009486
9487 // Check if global context allows code generation from
9488 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009489 if (context->allow_code_gen_from_strings()->IsFalse() &&
9490 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009491 return isolate->Throw(*isolate->factory()->NewError(
9492 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9493 }
9494
9495 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009496 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009497 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009498 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9501 context,
9502 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503 return *fun;
9504}
9505
9506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507static ObjectPair CompileGlobalEval(Isolate* isolate,
9508 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009509 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009510 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009511 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009512 Handle<Context> context = Handle<Context>(isolate->context());
9513 Handle<Context> global_context = Handle<Context>(context->global_context());
9514
9515 // Check if global context allows code generation from
9516 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009517 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9518 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009519 isolate->Throw(*isolate->factory()->NewError(
9520 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9521 return MakePair(Failure::Exception(), NULL);
9522 }
9523
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009524 // Deal with a normal eval call with a string argument. Compile it
9525 // and return the compiled function bound in the local context.
9526 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9527 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009529 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009530 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009531 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009532 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 Handle<JSFunction> compiled =
9534 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009535 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009536 return MakePair(*compiled, *receiver);
9537}
9538
9539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009540RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009541 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009544 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009545
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009546 // If "eval" didn't refer to the original GlobalEval, it's not a
9547 // direct call to eval.
9548 // (And even if it is, but the first argument isn't a string, just let
9549 // execution default to an indirect call to eval, which will also return
9550 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009551 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009552 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009553 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009554 }
9555
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009556 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009557 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009558 return CompileGlobalEval(isolate,
9559 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009560 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009561 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009562 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009563}
9564
9565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009566RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567 // This utility adjusts the property attributes for newly created Function
9568 // object ("new Function(...)") by changing the map.
9569 // All it does is changing the prototype property to enumerable
9570 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009571 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572 ASSERT(args.length() == 1);
9573 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009575 Handle<Map> map = func->shared()->is_classic_mode()
9576 ? isolate->function_instance_map()
9577 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009578
9579 ASSERT(func->map()->instance_type() == map->instance_type());
9580 ASSERT(func->map()->instance_size() == map->instance_size());
9581 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582 return *func;
9583}
9584
9585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009586RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009587 // Allocate a block of memory in NewSpace (filled with a filler).
9588 // Use as fallback for allocation in generated code when NewSpace
9589 // is full.
9590 ASSERT(args.length() == 1);
9591 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9592 int size = size_smi->value();
9593 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9594 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 Heap* heap = isolate->heap();
9596 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009597 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009598 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009599 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009600 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009602 }
9603 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009604 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009605}
9606
9607
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009608// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009609// array. Returns true if the element was pushed on the stack and
9610// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009611RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009612 ASSERT(args.length() == 2);
9613 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009614 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009615 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009616 int length = Smi::cast(array->length())->value();
9617 FixedArray* elements = FixedArray::cast(array->elements());
9618 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009620 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009621 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009622 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009623 { MaybeObject* maybe_obj =
9624 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009625 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009627 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009628}
9629
9630
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009631/**
9632 * A simple visitor visits every element of Array's.
9633 * The backend storage can be a fixed array for fast elements case,
9634 * or a dictionary for sparse array. Since Dictionary is a subtype
9635 * of FixedArray, the class can be used by both fast and slow cases.
9636 * The second parameter of the constructor, fast_elements, specifies
9637 * whether the storage is a FixedArray or Dictionary.
9638 *
9639 * An index limit is used to deal with the situation that a result array
9640 * length overflows 32-bit non-negative integer.
9641 */
9642class ArrayConcatVisitor {
9643 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009644 ArrayConcatVisitor(Isolate* isolate,
9645 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009646 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 isolate_(isolate),
9648 storage_(Handle<FixedArray>::cast(
9649 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009650 index_offset_(0u),
9651 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009652
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009653 ~ArrayConcatVisitor() {
9654 clear_storage();
9655 }
9656
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009657 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009659 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009660
9661 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 if (index < static_cast<uint32_t>(storage_->length())) {
9663 storage_->set(index, *elm);
9664 return;
9665 }
9666 // Our initial estimate of length was foiled, possibly by
9667 // getters on the arrays increasing the length of later arrays
9668 // during iteration.
9669 // This shouldn't happen in anything but pathological cases.
9670 SetDictionaryMode(index);
9671 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009672 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009674 Handle<SeededNumberDictionary> dict(
9675 SeededNumberDictionary::cast(*storage_));
9676 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009677 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009678 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009679 // Dictionary needed to grow.
9680 clear_storage();
9681 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009682 }
9683}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009684
9685 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9687 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009688 } else {
9689 index_offset_ += delta;
9690 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009691 }
9692
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009695 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009696 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009697 Handle<Map> map;
9698 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009699 map = isolate_->factory()->GetElementsTransitionMap(array,
9700 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009701 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009702 map = isolate_->factory()->GetElementsTransitionMap(array,
9703 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 }
9705 array->set_map(*map);
9706 array->set_length(*length);
9707 array->set_elements(*storage_);
9708 return array;
9709 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009710
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009711 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 // Convert storage to dictionary mode.
9713 void SetDictionaryMode(uint32_t index) {
9714 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009715 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009716 Handle<SeededNumberDictionary> slow_storage(
9717 isolate_->factory()->NewSeededNumberDictionary(
9718 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009719 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9720 for (uint32_t i = 0; i < current_length; i++) {
9721 HandleScope loop_scope;
9722 Handle<Object> element(current_storage->get(i));
9723 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009724 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009726 if (!new_storage.is_identical_to(slow_storage)) {
9727 slow_storage = loop_scope.CloseAndEscape(new_storage);
9728 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 }
9730 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009731 clear_storage();
9732 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 fast_elements_ = false;
9734 }
9735
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009736 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 isolate_->global_handles()->Destroy(
9738 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009739 }
9740
9741 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 storage_ = Handle<FixedArray>::cast(
9743 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009744 }
9745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009747 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 // Index after last seen index. Always less than or equal to
9749 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009750 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009751 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009752};
9753
9754
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009755static uint32_t EstimateElementCount(Handle<JSArray> array) {
9756 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9757 int element_count = 0;
9758 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009759 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009760 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 // Fast elements can't have lengths that are not representable by
9762 // a 32-bit signed integer.
9763 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9764 int fast_length = static_cast<int>(length);
9765 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9766 for (int i = 0; i < fast_length; i++) {
9767 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009768 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009769 break;
9770 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009771 case FAST_DOUBLE_ELEMENTS:
9772 // TODO(1810): Decide if it's worthwhile to implement this.
9773 UNREACHABLE();
9774 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009775 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009776 Handle<SeededNumberDictionary> dictionary(
9777 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 int capacity = dictionary->Capacity();
9779 for (int i = 0; i < capacity; i++) {
9780 Handle<Object> key(dictionary->KeyAt(i));
9781 if (dictionary->IsKey(*key)) {
9782 element_count++;
9783 }
9784 }
9785 break;
9786 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009787 case NON_STRICT_ARGUMENTS_ELEMENTS:
9788 case EXTERNAL_BYTE_ELEMENTS:
9789 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9790 case EXTERNAL_SHORT_ELEMENTS:
9791 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9792 case EXTERNAL_INT_ELEMENTS:
9793 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9794 case EXTERNAL_FLOAT_ELEMENTS:
9795 case EXTERNAL_DOUBLE_ELEMENTS:
9796 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009797 // External arrays are always dense.
9798 return length;
9799 }
9800 // As an estimate, we assume that the prototype doesn't contain any
9801 // inherited elements.
9802 return element_count;
9803}
9804
9805
9806
9807template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009808static void IterateExternalArrayElements(Isolate* isolate,
9809 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 bool elements_are_ints,
9811 bool elements_are_guaranteed_smis,
9812 ArrayConcatVisitor* visitor) {
9813 Handle<ExternalArrayClass> array(
9814 ExternalArrayClass::cast(receiver->elements()));
9815 uint32_t len = static_cast<uint32_t>(array->length());
9816
9817 ASSERT(visitor != NULL);
9818 if (elements_are_ints) {
9819 if (elements_are_guaranteed_smis) {
9820 for (uint32_t j = 0; j < len; j++) {
9821 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009822 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009823 visitor->visit(j, e);
9824 }
9825 } else {
9826 for (uint32_t j = 0; j < len; j++) {
9827 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009828 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009829 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9830 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9831 visitor->visit(j, e);
9832 } else {
9833 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 visitor->visit(j, e);
9836 }
9837 }
9838 }
9839 } else {
9840 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009842 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009843 visitor->visit(j, e);
9844 }
9845 }
9846}
9847
9848
9849// Used for sorting indices in a List<uint32_t>.
9850static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9851 uint32_t a = *ap;
9852 uint32_t b = *bp;
9853 return (a == b) ? 0 : (a < b) ? -1 : 1;
9854}
9855
9856
9857static void CollectElementIndices(Handle<JSObject> object,
9858 uint32_t range,
9859 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009860 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009861 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009862 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009863 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9865 uint32_t length = static_cast<uint32_t>(elements->length());
9866 if (range < length) length = range;
9867 for (uint32_t i = 0; i < length; i++) {
9868 if (!elements->get(i)->IsTheHole()) {
9869 indices->Add(i);
9870 }
9871 }
9872 break;
9873 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009874 case FAST_DOUBLE_ELEMENTS: {
9875 // TODO(1810): Decide if it's worthwhile to implement this.
9876 UNREACHABLE();
9877 break;
9878 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009879 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009880 Handle<SeededNumberDictionary> dict(
9881 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009882 uint32_t capacity = dict->Capacity();
9883 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009884 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009885 Handle<Object> k(dict->KeyAt(j));
9886 if (dict->IsKey(*k)) {
9887 ASSERT(k->IsNumber());
9888 uint32_t index = static_cast<uint32_t>(k->Number());
9889 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009890 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009891 }
9892 }
9893 }
9894 break;
9895 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009896 default: {
9897 int dense_elements_length;
9898 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009899 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009900 dense_elements_length =
9901 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009902 break;
9903 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009904 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009905 dense_elements_length =
9906 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 break;
9908 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009909 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009910 dense_elements_length =
9911 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009912 break;
9913 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009914 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 break;
9918 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009919 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009920 dense_elements_length =
9921 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 break;
9923 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009924 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009925 dense_elements_length =
9926 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 break;
9928 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009929 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009930 dense_elements_length =
9931 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009932 break;
9933 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009934 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009935 dense_elements_length =
9936 ExternalFloatArray::cast(object->elements())->length();
9937 break;
9938 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009939 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009940 dense_elements_length =
9941 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942 break;
9943 }
9944 default:
9945 UNREACHABLE();
9946 dense_elements_length = 0;
9947 break;
9948 }
9949 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9950 if (range <= length) {
9951 length = range;
9952 // We will add all indices, so we might as well clear it first
9953 // and avoid duplicates.
9954 indices->Clear();
9955 }
9956 for (uint32_t i = 0; i < length; i++) {
9957 indices->Add(i);
9958 }
9959 if (length == range) return; // All indices accounted for already.
9960 break;
9961 }
9962 }
9963
9964 Handle<Object> prototype(object->GetPrototype());
9965 if (prototype->IsJSObject()) {
9966 // The prototype will usually have no inherited element indices,
9967 // but we have to check.
9968 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9969 }
9970}
9971
9972
9973/**
9974 * A helper function that visits elements of a JSArray in numerical
9975 * order.
9976 *
9977 * The visitor argument called for each existing element in the array
9978 * with the element index and the element's value.
9979 * Afterwards it increments the base-index of the visitor by the array
9980 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009981 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009982 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983static bool IterateElements(Isolate* isolate,
9984 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009985 ArrayConcatVisitor* visitor) {
9986 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9987 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009988 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009989 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009990 // Run through the elements FixedArray and use HasElement and GetElement
9991 // to check the prototype for missing elements.
9992 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9993 int fast_length = static_cast<int>(length);
9994 ASSERT(fast_length <= elements->length());
9995 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 HandleScope loop_scope(isolate);
9997 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009998 if (!element_value->IsTheHole()) {
9999 visitor->visit(j, element_value);
10000 } else if (receiver->HasElement(j)) {
10001 // Call GetElement on receiver, not its prototype, or getters won't
10002 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010003 element_value = Object::GetElement(receiver, j);
10004 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010005 visitor->visit(j, element_value);
10006 }
10007 }
10008 break;
10009 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010010 case FAST_DOUBLE_ELEMENTS: {
10011 // TODO(1810): Decide if it's worthwhile to implement this.
10012 UNREACHABLE();
10013 break;
10014 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010015 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010016 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 List<uint32_t> indices(dict->Capacity() / 2);
10018 // Collect all indices in the object and the prototypes less
10019 // than length. This might introduce duplicates in the indices list.
10020 CollectElementIndices(receiver, length, &indices);
10021 indices.Sort(&compareUInt32);
10022 int j = 0;
10023 int n = indices.length();
10024 while (j < n) {
10025 HandleScope loop_scope;
10026 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010027 Handle<Object> element = Object::GetElement(receiver, index);
10028 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010029 visitor->visit(index, element);
10030 // Skip to next different index (i.e., omit duplicates).
10031 do {
10032 j++;
10033 } while (j < n && indices[j] == index);
10034 }
10035 break;
10036 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010037 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010038 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10039 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010040 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010041 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 visitor->visit(j, e);
10043 }
10044 break;
10045 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010046 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 break;
10055 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010056 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010059 break;
10060 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010061 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010062 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010064 break;
10065 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010066 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010067 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010068 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 break;
10070 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010071 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010072 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010074 break;
10075 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010076 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010077 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010079 break;
10080 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010081 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010082 IterateExternalArrayElements<ExternalDoubleArray, double>(
10083 isolate, receiver, false, false, visitor);
10084 break;
10085 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010086 default:
10087 UNREACHABLE();
10088 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010090 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010091 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010092}
10093
10094
10095/**
10096 * Array::concat implementation.
10097 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010098 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010099 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010100 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010101RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010102 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010105 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10106 int argument_count = static_cast<int>(arguments->length()->Number());
10107 RUNTIME_ASSERT(arguments->HasFastElements());
10108 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010109
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010110 // Pass 1: estimate the length and number of elements of the result.
10111 // The actual length can be larger if any of the arguments have getters
10112 // that mutate other arguments (but will otherwise be precise).
10113 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010114
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010115 uint32_t estimate_result_length = 0;
10116 uint32_t estimate_nof_elements = 0;
10117 {
10118 for (int i = 0; i < argument_count; i++) {
10119 HandleScope loop_scope;
10120 Handle<Object> obj(elements->get(i));
10121 uint32_t length_estimate;
10122 uint32_t element_estimate;
10123 if (obj->IsJSArray()) {
10124 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010125 // TODO(1810): Find out if it's worthwhile to properly support
10126 // arbitrary ElementsKinds. For now, pessimistically transition to
10127 // FAST_ELEMENTS.
10128 if (array->HasFastDoubleElements()) {
10129 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010130 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010131 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010132 length_estimate =
10133 static_cast<uint32_t>(array->length()->Number());
10134 element_estimate =
10135 EstimateElementCount(array);
10136 } else {
10137 length_estimate = 1;
10138 element_estimate = 1;
10139 }
10140 // Avoid overflows by capping at kMaxElementCount.
10141 if (JSObject::kMaxElementCount - estimate_result_length <
10142 length_estimate) {
10143 estimate_result_length = JSObject::kMaxElementCount;
10144 } else {
10145 estimate_result_length += length_estimate;
10146 }
10147 if (JSObject::kMaxElementCount - estimate_nof_elements <
10148 element_estimate) {
10149 estimate_nof_elements = JSObject::kMaxElementCount;
10150 } else {
10151 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010152 }
10153 }
10154 }
10155
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010156 // If estimated number of elements is more than half of length, a
10157 // fixed array (fast case) is more time and space-efficient than a
10158 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010159 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010160
10161 Handle<FixedArray> storage;
10162 if (fast_case) {
10163 // The backing storage array must have non-existing elements to
10164 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010165 storage = isolate->factory()->NewFixedArrayWithHoles(
10166 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010167 } else {
10168 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10169 uint32_t at_least_space_for = estimate_nof_elements +
10170 (estimate_nof_elements >> 2);
10171 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010172 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010173 }
10174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010175 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010176
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010177 for (int i = 0; i < argument_count; i++) {
10178 Handle<Object> obj(elements->get(i));
10179 if (obj->IsJSArray()) {
10180 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010182 return Failure::Exception();
10183 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010184 } else {
10185 visitor.visit(0, obj);
10186 visitor.increase_index_offset(1);
10187 }
10188 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010189
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010190 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010191}
10192
10193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194// This will not allocate (flatten the string), but it may run
10195// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010196RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 NoHandleAllocation ha;
10198 ASSERT(args.length() == 1);
10199
10200 CONVERT_CHECKED(String, string, args[0]);
10201 StringInputBuffer buffer(string);
10202 while (buffer.has_more()) {
10203 uint16_t character = buffer.GetNext();
10204 PrintF("%c", character);
10205 }
10206 return string;
10207}
10208
ager@chromium.org5ec48922009-05-05 07:25:34 +000010209// Moves all own elements of an object, that are below a limit, to positions
10210// starting at zero. All undefined values are placed after non-undefined values,
10211// and are followed by non-existing element. Does not change the length
10212// property.
10213// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010214RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010215 ASSERT(args.length() == 2);
10216 CONVERT_CHECKED(JSObject, object, args[0]);
10217 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10218 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219}
10220
10221
10222// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010223RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 ASSERT(args.length() == 2);
10225 CONVERT_CHECKED(JSArray, from, args[0]);
10226 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010227 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010228 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010229 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10231 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010232 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010233 } else if (new_elements->map() ==
10234 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010235 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010236 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010237 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010238 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010239 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010240 Object* new_map;
10241 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010242 to->set_map(Map::cast(new_map));
10243 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010245 Object* obj;
10246 { MaybeObject* maybe_obj = from->ResetElements();
10247 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10248 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010249 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 return to;
10251}
10252
10253
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010254// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010255RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010257 CONVERT_CHECKED(JSObject, object, args[0]);
10258 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010260 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10261 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010262 } else if (object->IsJSArray()) {
10263 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010265 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266 }
10267}
10268
10269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010272
10273 ASSERT_EQ(3, args.length());
10274
ager@chromium.orgac091b72010-05-05 07:34:42 +000010275 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010276 Handle<Object> key1 = args.at<Object>(1);
10277 Handle<Object> key2 = args.at<Object>(2);
10278
10279 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010280 if (!key1->ToArrayIndex(&index1)
10281 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010283 }
10284
ager@chromium.orgac091b72010-05-05 07:34:42 +000010285 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010286 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010288 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010289 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010290
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010291 RETURN_IF_EMPTY_HANDLE(
10292 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10293 RETURN_IF_EMPTY_HANDLE(
10294 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010296 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010297}
10298
10299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010301// might have elements. Can either return keys (positive integers) or
10302// intervals (pair of a negative integer (-start-1) followed by a
10303// positive (length)) or undefined values.
10304// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010305RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010307 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010308 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010310 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 // Create an array and get all the keys into it, then remove all the
10312 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010313 bool threw = false;
10314 Handle<FixedArray> keys =
10315 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10316 if (threw) return Failure::Exception();
10317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 int keys_length = keys->length();
10319 for (int i = 0; i < keys_length; i++) {
10320 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010321 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010322 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 // Zap invalid keys.
10324 keys->set_undefined(i);
10325 }
10326 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010329 ASSERT(array->HasFastElements() ||
10330 array->HasFastSmiOnlyElements() ||
10331 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010334 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010335 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010336 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010337 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010338 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 }
10344}
10345
10346
10347// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010348// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349// to the way accessors are implemented, it is set for both the getter
10350// and setter on the first call to DefineAccessor and ignored on
10351// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010352RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10354 // Compute attributes.
10355 PropertyAttributes attributes = NONE;
10356 if (args.length() == 5) {
10357 CONVERT_CHECKED(Smi, attrs, args[4]);
10358 int value = attrs->value();
10359 // Only attribute bits should be set.
10360 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10361 attributes = static_cast<PropertyAttributes>(value);
10362 }
10363
10364 CONVERT_CHECKED(JSObject, obj, args[0]);
10365 CONVERT_CHECKED(String, name, args[1]);
10366 CONVERT_CHECKED(Smi, flag, args[2]);
10367 CONVERT_CHECKED(JSFunction, fun, args[3]);
10368 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10369}
10370
10371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010372RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373 ASSERT(args.length() == 3);
10374 CONVERT_CHECKED(JSObject, obj, args[0]);
10375 CONVERT_CHECKED(String, name, args[1]);
10376 CONVERT_CHECKED(Smi, flag, args[2]);
10377 return obj->LookupAccessor(name, flag->value() == 0);
10378}
10379
10380
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010381#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010382RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010383 ASSERT(args.length() == 0);
10384 return Execution::DebugBreakHelper();
10385}
10386
10387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388// Helper functions for wrapping and unwrapping stack frame ids.
10389static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010390 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391 return Smi::FromInt(id >> 2);
10392}
10393
10394
10395static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10396 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10397}
10398
10399
10400// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010401// args[0]: debug event listener function to set or null or undefined for
10402// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010404RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010406 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10407 args[0]->IsUndefined() ||
10408 args[0]->IsNull());
10409 Handle<Object> callback = args.at<Object>(0);
10410 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010411 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414}
10415
10416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010417RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010418 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 isolate->stack_guard()->DebugBreak();
10420 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421}
10422
10423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010424static MaybeObject* DebugLookupResultValue(Heap* heap,
10425 Object* receiver,
10426 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010427 LookupResult* result,
10428 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010429 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010431 case NORMAL:
10432 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010433 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435 }
10436 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010437 case FIELD:
10438 value =
10439 JSObject::cast(
10440 result->holder())->FastPropertyAt(result->GetFieldIndex());
10441 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010442 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010443 }
10444 return value;
10445 case CONSTANT_FUNCTION:
10446 return result->GetConstantFunction();
10447 case CALLBACKS: {
10448 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010449 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010450 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10451 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010452 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010453 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010454 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010455 maybe_value = heap->isolate()->pending_exception();
10456 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010457 if (caught_exception != NULL) {
10458 *caught_exception = true;
10459 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010460 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010461 }
10462 return value;
10463 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010465 }
10466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010468 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010469 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010470 case CONSTANT_TRANSITION:
10471 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010473 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010475 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010477 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479}
10480
10481
ager@chromium.org32912102009-01-16 10:38:43 +000010482// Get debugger related details for an object property.
10483// args[0]: object holding property
10484// args[1]: name of the property
10485//
10486// The array returned contains the following information:
10487// 0: Property value
10488// 1: Property details
10489// 2: Property value is exception
10490// 3: Getter function if defined
10491// 4: Setter function if defined
10492// Items 2-4 are only filled if the property has either a getter or a setter
10493// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010494RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010495 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496
10497 ASSERT(args.length() == 2);
10498
10499 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10500 CONVERT_ARG_CHECKED(String, name, 1);
10501
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010502 // Make sure to set the current context to the context before the debugger was
10503 // entered (if the debugger is entered). The reason for switching context here
10504 // is that for some property lookups (accessors and interceptors) callbacks
10505 // into the embedding application can occour, and the embedding application
10506 // could have the assumption that its own global context is the current
10507 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010508 SaveContext save(isolate);
10509 if (isolate->debug()->InDebugger()) {
10510 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010511 }
10512
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010513 // Skip the global proxy as it has no properties and always delegates to the
10514 // real global object.
10515 if (obj->IsJSGlobalProxy()) {
10516 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10517 }
10518
10519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 // Check if the name is trivially convertible to an index and get the element
10521 // if so.
10522 uint32_t index;
10523 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010525 Object* element_or_char;
10526 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010528 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10529 return maybe_element_or_char;
10530 }
10531 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010532 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010534 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535 }
10536
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010537 // Find the number of objects making up this.
10538 int length = LocalPrototypeChainLength(*obj);
10539
10540 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010541 Handle<JSObject> jsproto = obj;
10542 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010543 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010544 jsproto->LocalLookup(*name, &result);
10545 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010546 // LookupResult is not GC safe as it holds raw object pointers.
10547 // GC can happen later in this code so put the required fields into
10548 // local variables using handles when required for later use.
10549 PropertyType result_type = result.type();
10550 Handle<Object> result_callback_obj;
10551 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10553 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010554 }
10555 Smi* property_details = result.GetPropertyDetails().AsSmi();
10556 // DebugLookupResultValue can cause GC so details from LookupResult needs
10557 // to be copied to handles before this.
10558 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010559 Object* raw_value;
10560 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010561 DebugLookupResultValue(isolate->heap(), *obj, *name,
10562 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010563 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010566
10567 // If the callback object is a fixed array then it contains JavaScript
10568 // getter and/or setter.
10569 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010570 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010571 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010573 details->set(0, *value);
10574 details->set(1, property_details);
10575 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010576 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010577 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10578 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010579 }
10580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010582 }
10583 if (i < length - 1) {
10584 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10585 }
10586 }
10587
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589}
10590
10591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010592RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
10595 ASSERT(args.length() == 2);
10596
10597 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10598 CONVERT_ARG_CHECKED(String, name, 1);
10599
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010600 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 obj->Lookup(*name, &result);
10602 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606}
10607
10608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609// Return the property type calculated from the property details.
10610// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 ASSERT(args.length() == 1);
10613 CONVERT_CHECKED(Smi, details, args[0]);
10614 PropertyType type = PropertyDetails(details).type();
10615 return Smi::FromInt(static_cast<int>(type));
10616}
10617
10618
10619// Return the property attribute calculated from the property details.
10620// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010621RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 ASSERT(args.length() == 1);
10623 CONVERT_CHECKED(Smi, details, args[0]);
10624 PropertyAttributes attributes = PropertyDetails(details).attributes();
10625 return Smi::FromInt(static_cast<int>(attributes));
10626}
10627
10628
10629// Return the property insertion index calculated from the property details.
10630// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010631RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010632 ASSERT(args.length() == 1);
10633 CONVERT_CHECKED(Smi, details, args[0]);
10634 int index = PropertyDetails(details).index();
10635 return Smi::FromInt(index);
10636}
10637
10638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639// Return property value from named interceptor.
10640// args[0]: object
10641// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010642RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010643 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 ASSERT(args.length() == 2);
10645 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10646 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10647 CONVERT_ARG_CHECKED(String, name, 1);
10648
10649 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010650 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651}
10652
10653
10654// Return element value from indexed interceptor.
10655// args[0]: object
10656// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010657RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 ASSERT(args.length() == 2);
10660 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10661 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10662 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10663
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010664 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665}
10666
10667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010668RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669 ASSERT(args.length() >= 1);
10670 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010671 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672 if (isolate->debug()->break_id() == 0 ||
10673 break_id != isolate->debug()->break_id()) {
10674 return isolate->Throw(
10675 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676 }
10677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679}
10680
10681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 ASSERT(args.length() == 1);
10685
10686 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010687 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010688 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10689 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010690 if (!maybe_result->ToObject(&result)) return maybe_result;
10691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692
10693 // Count all frames which are relevant to debugging stack trace.
10694 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010696 if (id == StackFrame::NO_ID) {
10697 // If there is no JavaScript stack frame count is 0.
10698 return Smi::FromInt(0);
10699 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010700
10701 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10702 n += it.frame()->GetInlineCount();
10703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 return Smi::FromInt(n);
10705}
10706
10707
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010708class FrameInspector {
10709 public:
10710 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010711 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010712 Isolate* isolate)
10713 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10714 // Calculate the deoptimized frame.
10715 if (frame->is_optimized()) {
10716 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010717 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010718 }
10719 has_adapted_arguments_ = frame_->has_adapted_arguments();
10720 is_optimized_ = frame_->is_optimized();
10721 }
10722
10723 ~FrameInspector() {
10724 // Get rid of the calculated deoptimized frame if any.
10725 if (deoptimized_frame_ != NULL) {
10726 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10727 isolate_);
10728 }
10729 }
10730
10731 int GetParametersCount() {
10732 return is_optimized_
10733 ? deoptimized_frame_->parameters_count()
10734 : frame_->ComputeParametersCount();
10735 }
10736 int expression_count() { return deoptimized_frame_->expression_count(); }
10737 Object* GetFunction() {
10738 return is_optimized_
10739 ? deoptimized_frame_->GetFunction()
10740 : frame_->function();
10741 }
10742 Object* GetParameter(int index) {
10743 return is_optimized_
10744 ? deoptimized_frame_->GetParameter(index)
10745 : frame_->GetParameter(index);
10746 }
10747 Object* GetExpression(int index) {
10748 return is_optimized_
10749 ? deoptimized_frame_->GetExpression(index)
10750 : frame_->GetExpression(index);
10751 }
10752
10753 // To inspect all the provided arguments the frame might need to be
10754 // replaced with the arguments frame.
10755 void SetArgumentsFrame(JavaScriptFrame* frame) {
10756 ASSERT(has_adapted_arguments_);
10757 frame_ = frame;
10758 is_optimized_ = frame_->is_optimized();
10759 ASSERT(!is_optimized_);
10760 }
10761
10762 private:
10763 JavaScriptFrame* frame_;
10764 DeoptimizedFrameInfo* deoptimized_frame_;
10765 Isolate* isolate_;
10766 bool is_optimized_;
10767 bool has_adapted_arguments_;
10768
10769 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10770};
10771
10772
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773static const int kFrameDetailsFrameIdIndex = 0;
10774static const int kFrameDetailsReceiverIndex = 1;
10775static const int kFrameDetailsFunctionIndex = 2;
10776static const int kFrameDetailsArgumentCountIndex = 3;
10777static const int kFrameDetailsLocalCountIndex = 4;
10778static const int kFrameDetailsSourcePositionIndex = 5;
10779static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010780static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010781static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010782static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010784
10785static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10786 JavaScriptFrame* frame) {
10787 SaveContext* save = isolate->save_context();
10788 while (save != NULL && !save->IsBelowFrame(frame)) {
10789 save = save->prev();
10790 }
10791 ASSERT(save != NULL);
10792 return save;
10793}
10794
10795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010796// Return an array with frame details
10797// args[0]: number: break id
10798// args[1]: number: frame index
10799//
10800// The array returned contains the following information:
10801// 0: Frame id
10802// 1: Receiver
10803// 2: Function
10804// 3: Argument count
10805// 4: Local count
10806// 5: Source position
10807// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010808// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010809// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810// Arguments name, value
10811// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010812// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010813RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010814 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815 ASSERT(args.length() == 2);
10816
10817 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010818 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010819 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10820 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010821 if (!maybe_check->ToObject(&check)) return maybe_check;
10822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010824 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825
10826 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010827 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010828 if (id == StackFrame::NO_ID) {
10829 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010831 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010833 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010834 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010836 if (index < count + it.frame()->GetInlineCount()) break;
10837 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010840
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010841 bool is_optimized = it.frame()->is_optimized();
10842
10843 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10844 if (is_optimized) {
10845 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010846 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010847 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010848 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850 // Traverse the saved contexts chain to find the active context for the
10851 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010852 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853
10854 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
10857 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010859 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010861 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010862 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010863 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010864
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010865 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010866 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010867 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010868 Handle<ScopeInfo> scope_info(shared->scope_info());
10869 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871 // Get the locals names and values into a temporary array.
10872 //
10873 // TODO(1240907): Hide compiler-introduced stack variables
10874 // (e.g. .result)? For users of the debugger, they will probably be
10875 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010877 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010879 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010880 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010881 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010882 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010883 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010884 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010885 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010887 // Get the context containing declarations.
10888 Handle<Context> context(
10889 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010890 for (; i < scope_info->LocalCount(); ++i) {
10891 Handle<String> name(scope_info->LocalName(i));
10892 VariableMode mode;
10893 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010894 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010895 locals->set(i * 2 + 1, context->get(
10896 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897 }
10898 }
10899
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010900 // Check whether this frame is positioned at return. If not top
10901 // frame or if the frame is optimized it cannot be at a return.
10902 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010903 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010905 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010906
10907 // If positioned just before return find the value to be returned and add it
10908 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010910 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010911 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010912 Address internal_frame_sp = NULL;
10913 while (!it2.done()) {
10914 if (it2.frame()->is_internal()) {
10915 internal_frame_sp = it2.frame()->sp();
10916 } else {
10917 if (it2.frame()->is_java_script()) {
10918 if (it2.frame()->id() == it.frame()->id()) {
10919 // The internal frame just before the JavaScript frame contains the
10920 // value to return on top. A debug break at return will create an
10921 // internal frame to store the return value (eax/rax/r0) before
10922 // entering the debug break exit frame.
10923 if (internal_frame_sp != NULL) {
10924 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010925 Handle<Object>(Memory::Object_at(internal_frame_sp),
10926 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010927 break;
10928 }
10929 }
10930 }
10931
10932 // Indicate that the previous frame was not an internal frame.
10933 internal_frame_sp = NULL;
10934 }
10935 it2.Advance();
10936 }
10937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938
10939 // Now advance to the arguments adapter frame (if any). It contains all
10940 // the provided parameters whereas the function frame always have the number
10941 // of arguments matching the functions parameters. The rest of the
10942 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010943 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010944 it.AdvanceToArgumentsFrame();
10945 frame_inspector.SetArgumentsFrame(it.frame());
10946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947
10948 // Find the number of arguments to fill. At least fill the number of
10949 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010950 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010951 if (argument_count < frame_inspector.GetParametersCount()) {
10952 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 }
10954
10955 // Calculate the size of the result.
10956 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010957 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010958 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010959 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960
10961 // Add the frame id.
10962 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10963
10964 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010965 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966
10967 // Add the arguments count.
10968 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10969
10970 // Add the locals count
10971 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010972 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973
10974 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010975 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10977 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 }
10980
10981 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010982 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010984 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010986
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010987 // Add flags to indicate information on whether this frame is
10988 // bit 0: invoked in the debugger context.
10989 // bit 1: optimized frame.
10990 // bit 2: inlined in optimized frame
10991 int flags = 0;
10992 if (*save->context() == *isolate->debug()->debug_context()) {
10993 flags |= 1 << 0;
10994 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010995 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010996 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010997 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010998 }
10999 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000
11001 // Fill the dynamic part.
11002 int details_index = kFrameDetailsFirstDynamicIndex;
11003
11004 // Add arguments name and value.
11005 for (int i = 0; i < argument_count; i++) {
11006 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011007 if (i < scope_info->ParameterCount()) {
11008 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 }
11012
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011013 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011014 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011015 // Get the value from the stack.
11016 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011018 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011019 }
11020 }
11021
11022 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011023 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 details->set(details_index++, locals->get(i));
11025 }
11026
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011027 // Add the value being returned.
11028 if (at_return) {
11029 details->set(details_index++, *return_value);
11030 }
11031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 // Add the receiver (same as in function frame).
11033 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11034 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011036 if (!receiver->IsJSObject() &&
11037 shared->is_classic_mode() &&
11038 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011039 // If the receiver is not a JSObject and the function is not a
11040 // builtin or strict-mode we have hit an optimization where a
11041 // value object is not converted into a wrapped JS objects. To
11042 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 // by creating correct wrapper object based on the calling frame's
11044 // global context.
11045 it.Advance();
11046 Handle<Context> calling_frames_global_context(
11047 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 receiver =
11049 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 }
11051 details->set(kFrameDetailsReceiverIndex, *receiver);
11052
11053 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055}
11056
11057
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011058// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011059static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011061 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011062 Handle<Context> context,
11063 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011065 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11066 VariableMode mode;
11067 InitializationFlag init_flag;
11068 int context_index = scope_info->ContextSlotIndex(
11069 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011070
whesse@chromium.org7b260152011-06-20 15:33:18 +000011071 RETURN_IF_EMPTY_HANDLE_VALUE(
11072 isolate,
11073 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011074 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011075 Handle<Object>(context->get(context_index), isolate),
11076 NONE,
11077 kNonStrictMode),
11078 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011079 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011080
11081 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082}
11083
11084
11085// Create a plain JSObject which materializes the local scope for the specified
11086// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011087static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011088 Isolate* isolate,
11089 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011090 FrameInspector* frame_inspector) {
11091 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011092 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011093 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094
11095 // Allocate and initialize a JSObject with all the arguments, stack locals
11096 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 Handle<JSObject> local_scope =
11098 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011099
11100 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011101 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011102 Handle<Object> value(
11103 i < frame_inspector->GetParametersCount() ?
11104 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11105
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011106 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011108 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011109 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011110 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011111 NONE,
11112 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011113 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011114 }
11115
11116 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011117 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011118 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011120 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011121 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011122 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011123 NONE,
11124 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011125 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011126 }
11127
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011128 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011129 // Third fill all context locals.
11130 Handle<Context> frame_context(Context::cast(frame->context()));
11131 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011132 if (!CopyContextLocalsToScopeObject(
11133 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011134 return Handle<JSObject>();
11135 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011137 // Finally copy any properties from the function context extension.
11138 // These will be variables introduced by eval.
11139 if (function_context->closure() == *function) {
11140 if (function_context->has_extension() &&
11141 !function_context->IsGlobalContext()) {
11142 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011143 bool threw = false;
11144 Handle<FixedArray> keys =
11145 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11146 if (threw) return Handle<JSObject>();
11147
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011148 for (int i = 0; i < keys->length(); i++) {
11149 // Names of variables introduced by eval are strings.
11150 ASSERT(keys->get(i)->IsString());
11151 Handle<String> key(String::cast(keys->get(i)));
11152 RETURN_IF_EMPTY_HANDLE_VALUE(
11153 isolate,
11154 SetProperty(local_scope,
11155 key,
11156 GetProperty(ext, key),
11157 NONE,
11158 kNonStrictMode),
11159 Handle<JSObject>());
11160 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011161 }
11162 }
11163 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011164
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011165 return local_scope;
11166}
11167
11168
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011169static Handle<JSObject> MaterializeLocalScope(
11170 Isolate* isolate,
11171 JavaScriptFrame* frame,
11172 int inlined_jsframe_index) {
11173 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11174 return MaterializeLocalScopeWithFrameInspector(isolate,
11175 frame,
11176 &frame_inspector);
11177}
11178
11179
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180// Create a plain JSObject which materializes the closure content for the
11181// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011182static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11183 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011184 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011186 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011187 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011189 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011190 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011191 Handle<JSObject> closure_scope =
11192 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011194 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011195 if (!CopyContextLocalsToScopeObject(
11196 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011197 return Handle<JSObject>();
11198 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011199
11200 // Finally copy any properties from the function context extension. This will
11201 // be variables introduced by eval.
11202 if (context->has_extension()) {
11203 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011204 bool threw = false;
11205 Handle<FixedArray> keys =
11206 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11207 if (threw) return Handle<JSObject>();
11208
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209 for (int i = 0; i < keys->length(); i++) {
11210 // Names of variables introduced by eval are strings.
11211 ASSERT(keys->get(i)->IsString());
11212 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 RETURN_IF_EMPTY_HANDLE_VALUE(
11214 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011215 SetProperty(closure_scope,
11216 key,
11217 GetProperty(ext, key),
11218 NONE,
11219 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011220 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011221 }
11222 }
11223
11224 return closure_scope;
11225}
11226
11227
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011228// Create a plain JSObject which materializes the scope for the specified
11229// catch context.
11230static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11231 Handle<Context> context) {
11232 ASSERT(context->IsCatchContext());
11233 Handle<String> name(String::cast(context->extension()));
11234 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11235 Handle<JSObject> catch_scope =
11236 isolate->factory()->NewJSObject(isolate->object_function());
11237 RETURN_IF_EMPTY_HANDLE_VALUE(
11238 isolate,
11239 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11240 Handle<JSObject>());
11241 return catch_scope;
11242}
11243
11244
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011245// Create a plain JSObject which materializes the block scope for the specified
11246// block context.
11247static Handle<JSObject> MaterializeBlockScope(
11248 Isolate* isolate,
11249 Handle<Context> context) {
11250 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011251 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011252
11253 // Allocate and initialize a JSObject with all the arguments, stack locals
11254 // heap locals and extension properties of the debugged function.
11255 Handle<JSObject> block_scope =
11256 isolate->factory()->NewJSObject(isolate->object_function());
11257
11258 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011259 if (!CopyContextLocalsToScopeObject(
11260 isolate, scope_info, context, block_scope)) {
11261 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011262 }
11263
11264 return block_scope;
11265}
11266
11267
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011268// Iterate over the actual scopes visible from a stack frame. The iteration
11269// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011270// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011271// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011272class ScopeIterator {
11273 public:
11274 enum ScopeType {
11275 ScopeTypeGlobal = 0,
11276 ScopeTypeLocal,
11277 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011278 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011279 ScopeTypeCatch,
11280 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011281 };
11282
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011283 ScopeIterator(Isolate* isolate,
11284 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011285 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 : isolate_(isolate),
11287 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011288 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011289 function_(JSFunction::cast(frame->function())),
11290 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011291 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011293 // Catch the case when the debugger stops in an internal function.
11294 Handle<SharedFunctionInfo> shared_info(function_->shared());
11295 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11296 if (shared_info->script() == isolate->heap()->undefined_value()) {
11297 while (context_->closure() == *function_) {
11298 context_ = Handle<Context>(context_->previous(), isolate_);
11299 }
11300 return;
11301 }
11302
11303 // Get the debug info (create it if it does not exist).
11304 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11305 // Return if ensuring debug info failed.
11306 return;
11307 }
11308 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11309
11310 // Find the break point where execution has stopped.
11311 BreakLocationIterator break_location_iterator(debug_info,
11312 ALL_BREAK_LOCATIONS);
11313 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11314 if (break_location_iterator.IsExit()) {
11315 // We are within the return sequence. At the momemt it is not possible to
11316 // get a source position which is consistent with the current scope chain.
11317 // Thus all nested with, catch and block contexts are skipped and we only
11318 // provide the function scope.
11319 if (scope_info->HasContext()) {
11320 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11321 } else {
11322 while (context_->closure() == *function_) {
11323 context_ = Handle<Context>(context_->previous(), isolate_);
11324 }
11325 }
11326 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11327 } else {
11328 // Reparse the code and analyze the scopes.
11329 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11330 Handle<Script> script(Script::cast(shared_info->script()));
11331 Scope* scope = NULL;
11332
11333 // Check whether we are in global, eval or function code.
11334 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11335 if (scope_info->Type() != FUNCTION_SCOPE) {
11336 // Global or eval code.
11337 CompilationInfo info(script);
11338 if (scope_info->Type() == GLOBAL_SCOPE) {
11339 info.MarkAsGlobal();
11340 } else {
11341 ASSERT(scope_info->Type() == EVAL_SCOPE);
11342 info.MarkAsEval();
11343 info.SetCallingContext(Handle<Context>(function_->context()));
11344 }
11345 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11346 scope = info.function()->scope();
11347 }
11348 } else {
11349 // Function code
11350 CompilationInfo info(shared_info);
11351 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11352 scope = info.function()->scope();
11353 }
11354 }
11355
11356 // Retrieve the scope chain for the current position.
11357 if (scope != NULL) {
11358 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11359 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11360 } else {
11361 // A failed reparse indicates that the preparser has diverged from the
11362 // parser or that the preparse data given to the initial parse has been
11363 // faulty. We fail in debug mode but in release mode we only provide the
11364 // information we get from the context chain but nothing about
11365 // completely stack allocated scopes or stack allocated locals.
11366 UNREACHABLE();
11367 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 }
11369 }
11370
11371 // More scopes?
11372 bool Done() { return context_.is_null(); }
11373
11374 // Move to the next scope.
11375 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011376 ScopeType scope_type = Type();
11377 if (scope_type == ScopeTypeGlobal) {
11378 // The global scope is always the last in the chain.
11379 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011380 context_ = Handle<Context>();
11381 return;
11382 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011383 if (nested_scope_chain_.is_empty()) {
11384 context_ = Handle<Context>(context_->previous(), isolate_);
11385 } else {
11386 if (nested_scope_chain_.last()->HasContext()) {
11387 ASSERT(context_->previous() != NULL);
11388 context_ = Handle<Context>(context_->previous(), isolate_);
11389 }
11390 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011391 }
11392 }
11393
11394 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011395 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011396 if (!nested_scope_chain_.is_empty()) {
11397 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11398 switch (scope_info->Type()) {
11399 case FUNCTION_SCOPE:
11400 ASSERT(context_->IsFunctionContext() ||
11401 !scope_info->HasContext());
11402 return ScopeTypeLocal;
11403 case GLOBAL_SCOPE:
11404 ASSERT(context_->IsGlobalContext());
11405 return ScopeTypeGlobal;
11406 case WITH_SCOPE:
11407 ASSERT(context_->IsWithContext());
11408 return ScopeTypeWith;
11409 case CATCH_SCOPE:
11410 ASSERT(context_->IsCatchContext());
11411 return ScopeTypeCatch;
11412 case BLOCK_SCOPE:
11413 ASSERT(!scope_info->HasContext() ||
11414 context_->IsBlockContext());
11415 return ScopeTypeBlock;
11416 case EVAL_SCOPE:
11417 UNREACHABLE();
11418 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011419 }
11420 if (context_->IsGlobalContext()) {
11421 ASSERT(context_->global()->IsGlobalObject());
11422 return ScopeTypeGlobal;
11423 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011425 return ScopeTypeClosure;
11426 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011427 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011428 return ScopeTypeCatch;
11429 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011430 if (context_->IsBlockContext()) {
11431 return ScopeTypeBlock;
11432 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011433 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011434 return ScopeTypeWith;
11435 }
11436
11437 // Return the JavaScript object with the content of the current scope.
11438 Handle<JSObject> ScopeObject() {
11439 switch (Type()) {
11440 case ScopeIterator::ScopeTypeGlobal:
11441 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011442 case ScopeIterator::ScopeTypeLocal:
11443 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011444 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011445 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011446 case ScopeIterator::ScopeTypeWith:
11447 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011448 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11449 case ScopeIterator::ScopeTypeCatch:
11450 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011451 case ScopeIterator::ScopeTypeClosure:
11452 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011454 case ScopeIterator::ScopeTypeBlock:
11455 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011456 }
11457 UNREACHABLE();
11458 return Handle<JSObject>();
11459 }
11460
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011461 Handle<ScopeInfo> CurrentScopeInfo() {
11462 if (!nested_scope_chain_.is_empty()) {
11463 return nested_scope_chain_.last();
11464 } else if (context_->IsBlockContext()) {
11465 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11466 } else if (context_->IsFunctionContext()) {
11467 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11468 }
11469 return Handle<ScopeInfo>::null();
11470 }
11471
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472 // Return the context for this scope. For the local context there might not
11473 // be an actual context.
11474 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011475 if (Type() == ScopeTypeGlobal ||
11476 nested_scope_chain_.is_empty()) {
11477 return context_;
11478 } else if (nested_scope_chain_.last()->HasContext()) {
11479 return context_;
11480 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011481 return Handle<Context>();
11482 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483 }
11484
11485#ifdef DEBUG
11486 // Debug print of the content of the current scope.
11487 void DebugPrint() {
11488 switch (Type()) {
11489 case ScopeIterator::ScopeTypeGlobal:
11490 PrintF("Global:\n");
11491 CurrentContext()->Print();
11492 break;
11493
11494 case ScopeIterator::ScopeTypeLocal: {
11495 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011496 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011497 if (!CurrentContext().is_null()) {
11498 CurrentContext()->Print();
11499 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011500 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 if (extension->IsJSContextExtensionObject()) {
11502 extension->Print();
11503 }
11504 }
11505 }
11506 break;
11507 }
11508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011509 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011510 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011511 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011514 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011515 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011516 CurrentContext()->extension()->Print();
11517 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011518 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011520 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011521 PrintF("Closure:\n");
11522 CurrentContext()->Print();
11523 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011524 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011525 if (extension->IsJSContextExtensionObject()) {
11526 extension->Print();
11527 }
11528 }
11529 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011530
11531 default:
11532 UNREACHABLE();
11533 }
11534 PrintF("\n");
11535 }
11536#endif
11537
11538 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011540 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011541 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011542 Handle<JSFunction> function_;
11543 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011544 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545
11546 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11547};
11548
11549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011550RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011552 ASSERT(args.length() == 2);
11553
11554 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011555 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011556 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11557 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011558 if (!maybe_check->ToObject(&check)) return maybe_check;
11559 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011560 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11561
11562 // Get the frame where the debugging is performed.
11563 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011564 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011565 JavaScriptFrame* frame = it.frame();
11566
11567 // Count the visible scopes.
11568 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011569 for (ScopeIterator it(isolate, frame, 0);
11570 !it.Done();
11571 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011572 n++;
11573 }
11574
11575 return Smi::FromInt(n);
11576}
11577
11578
11579static const int kScopeDetailsTypeIndex = 0;
11580static const int kScopeDetailsObjectIndex = 1;
11581static const int kScopeDetailsSize = 2;
11582
11583// Return an array with scope details
11584// args[0]: number: break id
11585// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011586// args[2]: number: inlined frame index
11587// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011588//
11589// The array returned contains the following information:
11590// 0: Scope type
11591// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011592RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011594 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011595
11596 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011597 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011598 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11599 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011600 if (!maybe_check->ToObject(&check)) return maybe_check;
11601 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011602 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011603 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011604 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605
11606 // Get the frame where the debugging is performed.
11607 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011608 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011609 JavaScriptFrame* frame = frame_it.frame();
11610
11611 // Find the requested scope.
11612 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011613 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011614 for (; !it.Done() && n < index; it.Next()) {
11615 n++;
11616 }
11617 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011618 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011619 }
11620
11621 // Calculate the size of the result.
11622 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011624
11625 // Fill in scope details.
11626 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011627 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011629 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011632}
11633
11634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011637 ASSERT(args.length() == 0);
11638
11639#ifdef DEBUG
11640 // Print the scopes for the top frame.
11641 StackFrameLocator locator;
11642 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011643 for (ScopeIterator it(isolate, frame, 0);
11644 !it.Done();
11645 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011646 it.DebugPrint();
11647 }
11648#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011650}
11651
11652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011655 ASSERT(args.length() == 1);
11656
11657 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011658 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011659 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11660 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011661 if (!maybe_result->ToObject(&result)) return maybe_result;
11662 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011663
11664 // Count all archived V8 threads.
11665 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011666 for (ThreadState* thread =
11667 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011668 thread != NULL;
11669 thread = thread->Next()) {
11670 n++;
11671 }
11672
11673 // Total number of threads is current thread and archived threads.
11674 return Smi::FromInt(n + 1);
11675}
11676
11677
11678static const int kThreadDetailsCurrentThreadIndex = 0;
11679static const int kThreadDetailsThreadIdIndex = 1;
11680static const int kThreadDetailsSize = 2;
11681
11682// Return an array with thread details
11683// args[0]: number: break id
11684// args[1]: number: thread index
11685//
11686// The array returned contains the following information:
11687// 0: Is current thread?
11688// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011689RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011691 ASSERT(args.length() == 2);
11692
11693 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011694 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011695 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11696 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011697 if (!maybe_check->ToObject(&check)) return maybe_check;
11698 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011699 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11700
11701 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 Handle<FixedArray> details =
11703 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011704
11705 // Thread index 0 is current thread.
11706 if (index == 0) {
11707 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 details->set(kThreadDetailsCurrentThreadIndex,
11709 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011710 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011711 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011712 } else {
11713 // Find the thread with the requested index.
11714 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715 ThreadState* thread =
11716 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011717 while (index != n && thread != NULL) {
11718 thread = thread->Next();
11719 n++;
11720 }
11721 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011722 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011723 }
11724
11725 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011726 details->set(kThreadDetailsCurrentThreadIndex,
11727 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011728 details->set(kThreadDetailsThreadIdIndex,
11729 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011730 }
11731
11732 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011734}
11735
11736
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011737// Sets the disable break state
11738// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011740 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011741 ASSERT(args.length() == 1);
11742 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743 isolate->debug()->set_disable_break(disable_break);
11744 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011745}
11746
11747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011748RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750 ASSERT(args.length() == 1);
11751
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011752 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11753 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 // Find the number of break points
11755 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011756 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759 Handle<FixedArray>::cast(break_locations));
11760}
11761
11762
11763// Set a break point in a function
11764// args[0]: function
11765// args[1]: number: break source position (within the function source)
11766// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011767RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011768 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011769 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011770 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11771 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11773 RUNTIME_ASSERT(source_position >= 0);
11774 Handle<Object> break_point_object_arg = args.at<Object>(2);
11775
11776 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011777 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11778 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011779
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011780 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781}
11782
11783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11785 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011786 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 // Iterate the heap looking for SharedFunctionInfo generated from the
11788 // script. The inner most SharedFunctionInfo containing the source position
11789 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011790 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011791 // which is found is not compiled it is compiled and the heap is iterated
11792 // again as the compilation might create inner functions from the newly
11793 // compiled function and the actual requested break point might be in one of
11794 // these functions.
11795 bool done = false;
11796 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011797 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011800 { // Extra scope for iterator and no-allocation.
11801 isolate->heap()->EnsureHeapIsIterable();
11802 AssertNoAllocation no_alloc_during_heap_iteration;
11803 HeapIterator iterator;
11804 for (HeapObject* obj = iterator.next();
11805 obj != NULL; obj = iterator.next()) {
11806 if (obj->IsSharedFunctionInfo()) {
11807 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11808 if (shared->script() == *script) {
11809 // If the SharedFunctionInfo found has the requested script data and
11810 // contains the source position it is a candidate.
11811 int start_position = shared->function_token_position();
11812 if (start_position == RelocInfo::kNoPosition) {
11813 start_position = shared->start_position();
11814 }
11815 if (start_position <= position &&
11816 position <= shared->end_position()) {
11817 // If there is no candidate or this function is within the current
11818 // candidate this is the new candidate.
11819 if (target.is_null()) {
11820 target_start_position = start_position;
11821 target = shared;
11822 } else {
11823 if (target_start_position == start_position &&
11824 shared->end_position() == target->end_position()) {
11825 // If a top-level function contain only one function
11826 // declartion the source for the top-level and the
11827 // function is the same. In that case prefer the non
11828 // top-level function.
11829 if (!shared->is_toplevel()) {
11830 target_start_position = start_position;
11831 target = shared;
11832 }
11833 } else if (target_start_position <= start_position &&
11834 shared->end_position() <= target->end_position()) {
11835 // This containment check includes equality as a function
11836 // inside a top-level function can share either start or end
11837 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011838 target_start_position = start_position;
11839 target = shared;
11840 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 }
11842 }
11843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011845 } // End for loop.
11846 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011848 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850 }
11851
11852 // If the candidate found is compiled we are done. NOTE: when lazy
11853 // compilation of inner functions is introduced some additional checking
11854 // needs to be done here to compile inner functions.
11855 done = target->is_compiled();
11856 if (!done) {
11857 // If the candidate is not compiled compile it to reveal any inner
11858 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011859 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011860 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011861 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862
11863 return *target;
11864}
11865
11866
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011867// Changes the state of a break point in a script and returns source position
11868// where break point was set. NOTE: Regarding performance see the NOTE for
11869// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011870// args[0]: script to set break point in
11871// args[1]: number: break source position (within the script source)
11872// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011873RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011875 ASSERT(args.length() == 3);
11876 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11877 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11878 RUNTIME_ASSERT(source_position >= 0);
11879 Handle<Object> break_point_object_arg = args.at<Object>(2);
11880
11881 // Get the script from the script wrapper.
11882 RUNTIME_ASSERT(wrapper->value()->IsScript());
11883 Handle<Script> script(Script::cast(wrapper->value()));
11884
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011885 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011887 if (!result->IsUndefined()) {
11888 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11889 // Find position within function. The script position might be before the
11890 // source position of the first function.
11891 int position;
11892 if (shared->start_position() > source_position) {
11893 position = 0;
11894 } else {
11895 position = source_position - shared->start_position();
11896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011897 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011898 position += shared->start_position();
11899 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902}
11903
11904
11905// Clear a break point
11906// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011907RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909 ASSERT(args.length() == 1);
11910 Handle<Object> break_point_object_arg = args.at<Object>(0);
11911
11912 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916}
11917
11918
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011919// Change the state of break on exceptions.
11920// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11921// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011922RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011925 RUNTIME_ASSERT(args[0]->IsNumber());
11926 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011928 // If the number doesn't match an enum value, the ChangeBreakOnException
11929 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011930 ExceptionBreakType type =
11931 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011932 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 isolate->debug()->ChangeBreakOnException(type, enable);
11934 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935}
11936
11937
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011938// Returns the state of break on exceptions
11939// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011940RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011942 ASSERT(args.length() == 1);
11943 RUNTIME_ASSERT(args[0]->IsNumber());
11944
11945 ExceptionBreakType type =
11946 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011948 return Smi::FromInt(result);
11949}
11950
11951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952// Prepare for stepping
11953// args[0]: break id for checking execution state
11954// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011955// args[2]: number of times to perform the step, for step out it is the number
11956// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011957RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011959 ASSERT(args.length() == 3);
11960 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011961 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011962 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11963 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011964 if (!maybe_check->ToObject(&check)) return maybe_check;
11965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968 }
11969
11970 // Get the step action and check validity.
11971 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11972 if (step_action != StepIn &&
11973 step_action != StepNext &&
11974 step_action != StepOut &&
11975 step_action != StepInMin &&
11976 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011977 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978 }
11979
11980 // Get the number of steps.
11981 int step_count = NumberToInt32(args[2]);
11982 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984 }
11985
ager@chromium.orga1645e22009-09-09 19:27:10 +000011986 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011987 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011989 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011990 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11991 step_count);
11992 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011993}
11994
11995
11996// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011997RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011999 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012000 isolate->debug()->ClearStepping();
12001 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002}
12003
12004
12005// Creates a copy of the with context chain. The copy of the context chain is
12006// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012007static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12008 Handle<JSFunction> function,
12009 Handle<Context> base,
12010 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012011 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012012 HandleScope scope(isolate);
12013 List<Handle<ScopeInfo> > scope_chain;
12014 List<Handle<Context> > context_chain;
12015
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012016 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012017 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12018 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12019 ASSERT(!it.Done());
12020 scope_chain.Add(it.CurrentScopeInfo());
12021 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012022 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012023
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012024 // At the end of the chain. Return the base context to link to.
12025 Handle<Context> context = base;
12026
12027 // Iteratively copy and or materialize the nested contexts.
12028 while (!scope_chain.is_empty()) {
12029 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12030 Handle<Context> current = context_chain.RemoveLast();
12031 ASSERT(!(scope_info->HasContext() & current.is_null()));
12032
12033 if (scope_info->Type() == CATCH_SCOPE) {
12034 Handle<String> name(String::cast(current->extension()));
12035 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12036 context =
12037 isolate->factory()->NewCatchContext(function,
12038 context,
12039 name,
12040 thrown_object);
12041 } else if (scope_info->Type() == BLOCK_SCOPE) {
12042 // Materialize the contents of the block scope into a JSObject.
12043 Handle<JSObject> block_scope_object =
12044 MaterializeBlockScope(isolate, current);
12045 if (block_scope_object.is_null()) {
12046 return Handle<Context>::null();
12047 }
12048 // Allocate a new function context for the debug evaluation and set the
12049 // extension object.
12050 Handle<Context> new_context =
12051 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12052 function);
12053 new_context->set_extension(*block_scope_object);
12054 new_context->set_previous(*context);
12055 context = new_context;
12056 } else {
12057 ASSERT(scope_info->Type() == WITH_SCOPE);
12058 ASSERT(current->IsWithContext());
12059 Handle<JSObject> extension(JSObject::cast(current->extension()));
12060 context =
12061 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012062 }
erikcorry0ad885c2011-11-21 13:51:57 +000012063 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012064
12065 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012066}
12067
12068
12069// Helper function to find or create the arguments object for
12070// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012071static Handle<Object> GetArgumentsObject(Isolate* isolate,
12072 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012073 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012074 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075 Handle<Context> function_context) {
12076 // Try to find the value of 'arguments' to pass as parameter. If it is not
12077 // found (that is the debugged function does not reference 'arguments' and
12078 // does not support eval) then create an 'arguments' object.
12079 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012080 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012081 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012082 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084 }
12085 }
12086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012087 if (scope_info->HasHeapAllocatedLocals()) {
12088 VariableMode mode;
12089 InitializationFlag init_flag;
12090 index = scope_info->ContextSlotIndex(
12091 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094 }
12095 }
12096
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012097 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12098 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099 Handle<JSObject> arguments =
12100 isolate->factory()->NewArgumentsObject(function, length);
12101 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012102
12103 AssertNoAllocation no_gc;
12104 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012106 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012108 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012109 return arguments;
12110}
12111
12112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113static const char kSourceStr[] =
12114 "(function(arguments,__source__){return eval(__source__);})";
12115
12116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012118// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119// extension part has all the parameters and locals of the function on the
12120// stack frame. A function which calls eval with the code to evaluate is then
12121// compiled in this context and called in this context. As this context
12122// replaces the context of the function on the stack frame a new (empty)
12123// function is created as well to be used as the closure for the context.
12124// This function and the context acts as replacements for the function on the
12125// stack frame presenting the same view of the values of parameters and
12126// local variables as if the piece of JavaScript was evaluated at the point
12127// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012128RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130
12131 // Check the execution state and decode arguments frame and source to be
12132 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012133 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012134 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012135 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12136 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012137 if (!maybe_check_result->ToObject(&check_result)) {
12138 return maybe_check_result;
12139 }
12140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012142 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012143 CONVERT_ARG_CHECKED(String, source, 3);
12144 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12145 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012146
12147 // Handle the processing of break.
12148 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149
12150 // Get the frame where the debugging is performed.
12151 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012152 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012154 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12155 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012156 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157
12158 // Traverse the saved contexts chain to find the active context for the
12159 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012160 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12161
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012162 SaveContext savex(isolate);
12163 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164
12165 // Create the (empty) function replacing the function on the stack frame for
12166 // the purpose of evaluating in the context created below. It is important
12167 // that this function does not describe any parameters and local variables
12168 // in the context. If it does then this will cause problems with the lookup
12169 // in Context::Lookup, where context slots for parameters and local variables
12170 // are looked at before the extension object.
12171 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12173 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174 go_between->set_context(function->context());
12175#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012176 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12177 ASSERT(go_between_scope_info->ParameterCount() == 0);
12178 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179#endif
12180
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012181 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012182 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12183 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012184 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185
12186 // Allocate a new context for the debug evaluation and set the extension
12187 // object build.
12188 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012189 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12190 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012191 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012192 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012193 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012194 Handle<Context> function_context;
12195 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012196 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012197 function_context = Handle<Context>(frame_context->declaration_context());
12198 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012199 context = CopyNestedScopeContextChain(isolate,
12200 go_between,
12201 context,
12202 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012203 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012205 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012206 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012207 context =
12208 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012209 }
12210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 // Wrap the evaluation statement in a new function compiled in the newly
12212 // created context. The function has one parameter which has to be called
12213 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012214 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012217 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 isolate->factory()->NewStringFromAscii(
12219 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012220
12221 // Currently, the eval code will be executed in non-strict mode,
12222 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012223 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012224 Compiler::CompileEval(function_source,
12225 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012226 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012227 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012228 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012229 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012230 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012231 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232
12233 // Invoke the result of the compilation to get the evaluation function.
12234 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 Handle<Object> evaluation_function =
12237 Execution::Call(compiled_function, receiver, 0, NULL,
12238 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012239 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012240
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012241 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012242 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012243 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012244 scope_info,
12245 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246
12247 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012248 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012250 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12251 receiver,
12252 ARRAY_SIZE(argv),
12253 argv,
12254 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012255 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012256
12257 // Skip the global proxy as it has no properties and always delegates to the
12258 // real global object.
12259 if (result->IsJSGlobalProxy()) {
12260 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12261 }
12262
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 return *result;
12264}
12265
12266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012267RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269
12270 // Check the execution state and decode arguments frame and source to be
12271 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012272 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012273 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012274 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12275 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012276 if (!maybe_check_result->ToObject(&check_result)) {
12277 return maybe_check_result;
12278 }
12279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012280 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012281 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012282 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012283
12284 // Handle the processing of break.
12285 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012286
12287 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012288 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012289 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012291 top = top->prev();
12292 }
12293 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012294 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012295 }
12296
12297 // Get the global context now set to the top context from before the
12298 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012301 bool is_global = true;
12302
12303 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012304 // Create a new with context with the additional context information between
12305 // the context of the debugged function and the eval code to be executed.
12306 context = isolate->factory()->NewWithContext(
12307 Handle<JSFunction>(context->closure()),
12308 context,
12309 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012310 is_global = false;
12311 }
12312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012313 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012314 // Currently, the eval code will be executed in non-strict mode,
12315 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012316 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012317 Compiler::CompileEval(source,
12318 context,
12319 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012320 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012321 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012322 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012323 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012324 Handle<JSFunction>(
12325 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12326 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012327
12328 // Invoke the result of the compilation to get the evaluation function.
12329 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012330 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012331 Handle<Object> result =
12332 Execution::Call(compiled_function, receiver, 0, NULL,
12333 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012334 // Clear the oneshot breakpoints so that the debugger does not step further.
12335 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012336 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012337 return *result;
12338}
12339
12340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012341RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012342 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012343 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012345 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012346 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347
12348 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012349 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012350 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12351 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12352 // because using
12353 // instances->set(i, *GetScriptWrapper(script))
12354 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012355 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012356 Handle<JSValue> wrapper = GetScriptWrapper(script);
12357 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 }
12359
12360 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012361 Handle<JSObject> result =
12362 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012363 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012364 return *result;
12365}
12366
12367
12368// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012369static int DebugReferencedBy(HeapIterator* iterator,
12370 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012371 Object* instance_filter, int max_references,
12372 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012373 JSFunction* arguments_function) {
12374 NoHandleAllocation ha;
12375 AssertNoAllocation no_alloc;
12376
12377 // Iterate the heap.
12378 int count = 0;
12379 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012380 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012381 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012382 (max_references == 0 || count < max_references)) {
12383 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 if (heap_obj->IsJSObject()) {
12385 // Skip context extension objects and argument arrays as these are
12386 // checked in the context of functions using them.
12387 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012388 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012389 obj->map()->constructor() == arguments_function) {
12390 continue;
12391 }
12392
12393 // Check if the JS object has a reference to the object looked for.
12394 if (obj->ReferencesObject(target)) {
12395 // Check instance filter if supplied. This is normally used to avoid
12396 // references from mirror objects (see Runtime_IsInPrototypeChain).
12397 if (!instance_filter->IsUndefined()) {
12398 Object* V = obj;
12399 while (true) {
12400 Object* prototype = V->GetPrototype();
12401 if (prototype->IsNull()) {
12402 break;
12403 }
12404 if (instance_filter == prototype) {
12405 obj = NULL; // Don't add this object.
12406 break;
12407 }
12408 V = prototype;
12409 }
12410 }
12411
12412 if (obj != NULL) {
12413 // Valid reference found add to instance array if supplied an update
12414 // count.
12415 if (instances != NULL && count < instances_size) {
12416 instances->set(count, obj);
12417 }
12418 last = obj;
12419 count++;
12420 }
12421 }
12422 }
12423 }
12424
12425 // Check for circular reference only. This can happen when the object is only
12426 // referenced from mirrors and has a circular reference in which case the
12427 // object is not really alive and would have been garbage collected if not
12428 // referenced from the mirror.
12429 if (count == 1 && last == target) {
12430 count = 0;
12431 }
12432
12433 // Return the number of referencing objects found.
12434 return count;
12435}
12436
12437
12438// Scan the heap for objects with direct references to an object
12439// args[0]: the object to find references to
12440// args[1]: constructor function for instances to exclude (Mirror)
12441// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012442RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012443 ASSERT(args.length() == 3);
12444
12445 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012446 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12447 // The heap iterator reserves the right to do a GC to make the heap iterable.
12448 // Due to the GC above we know it won't need to do that, but it seems cleaner
12449 // to get the heap iterator constructed before we start having unprotected
12450 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012451
12452 // Check parameters.
12453 CONVERT_CHECKED(JSObject, target, args[0]);
12454 Object* instance_filter = args[1];
12455 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12456 instance_filter->IsJSObject());
12457 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12458 RUNTIME_ASSERT(max_references >= 0);
12459
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012461 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012462 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012463 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012464 JSFunction* arguments_function =
12465 JSFunction::cast(arguments_boilerplate->map()->constructor());
12466
12467 // Get the number of referencing objects.
12468 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012469 HeapIterator heap_iterator;
12470 count = DebugReferencedBy(&heap_iterator,
12471 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012472 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012473
12474 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012475 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012476 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012477 if (!maybe_object->ToObject(&object)) return maybe_object;
12478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012479 FixedArray* instances = FixedArray::cast(object);
12480
12481 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012482 // AllocateFixedArray above does not make the heap non-iterable.
12483 ASSERT(HEAP->IsHeapIterable());
12484 HeapIterator heap_iterator2;
12485 count = DebugReferencedBy(&heap_iterator2,
12486 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012487 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012488
12489 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012490 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012491 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012492 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012493 if (!maybe_result->ToObject(&result)) return maybe_result;
12494 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012495}
12496
12497
12498// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012499static int DebugConstructedBy(HeapIterator* iterator,
12500 JSFunction* constructor,
12501 int max_references,
12502 FixedArray* instances,
12503 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012504 AssertNoAllocation no_alloc;
12505
12506 // Iterate the heap.
12507 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012508 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012509 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510 (max_references == 0 || count < max_references)) {
12511 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512 if (heap_obj->IsJSObject()) {
12513 JSObject* obj = JSObject::cast(heap_obj);
12514 if (obj->map()->constructor() == constructor) {
12515 // Valid reference found add to instance array if supplied an update
12516 // count.
12517 if (instances != NULL && count < instances_size) {
12518 instances->set(count, obj);
12519 }
12520 count++;
12521 }
12522 }
12523 }
12524
12525 // Return the number of referencing objects found.
12526 return count;
12527}
12528
12529
12530// Scan the heap for objects constructed by a specific function.
12531// args[0]: the constructor to find instances of
12532// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012534 ASSERT(args.length() == 2);
12535
12536 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012537 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012538
12539 // Check parameters.
12540 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12541 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12542 RUNTIME_ASSERT(max_references >= 0);
12543
12544 // Get the number of referencing objects.
12545 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012546 HeapIterator heap_iterator;
12547 count = DebugConstructedBy(&heap_iterator,
12548 constructor,
12549 max_references,
12550 NULL,
12551 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012552
12553 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012554 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012556 if (!maybe_object->ToObject(&object)) return maybe_object;
12557 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012558 FixedArray* instances = FixedArray::cast(object);
12559
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012560 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012561 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012562 HeapIterator heap_iterator2;
12563 count = DebugConstructedBy(&heap_iterator2,
12564 constructor,
12565 max_references,
12566 instances,
12567 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012568
12569 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012570 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12572 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012573 if (!maybe_result->ToObject(&result)) return maybe_result;
12574 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012575 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012576}
12577
12578
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012579// Find the effective prototype object as returned by __proto__.
12580// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012582 ASSERT(args.length() == 1);
12583
12584 CONVERT_CHECKED(JSObject, obj, args[0]);
12585
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012586 // Use the __proto__ accessor.
12587 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012588}
12589
12590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012592 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012593 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012595}
12596
12597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012598RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012599#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012600 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012601 ASSERT(args.length() == 1);
12602 // Get the function and make sure it is compiled.
12603 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012604 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012605 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012606 return Failure::Exception();
12607 }
12608 func->code()->PrintLn();
12609#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012611}
ager@chromium.org9085a012009-05-11 19:22:57 +000012612
12613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012614RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012615#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012616 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012617 ASSERT(args.length() == 1);
12618 // Get the function and make sure it is compiled.
12619 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012620 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012621 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012622 return Failure::Exception();
12623 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012624 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012625#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012626 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012627}
12628
12629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012630RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012631 NoHandleAllocation ha;
12632 ASSERT(args.length() == 1);
12633
12634 CONVERT_CHECKED(JSFunction, f, args[0]);
12635 return f->shared()->inferred_name();
12636}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012637
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012638
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012639static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12640 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012641 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012642 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012643 int counter = 0;
12644 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012645 for (HeapObject* obj = iterator->next();
12646 obj != NULL;
12647 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 ASSERT(obj != NULL);
12649 if (!obj->IsSharedFunctionInfo()) {
12650 continue;
12651 }
12652 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12653 if (shared->script() != script) {
12654 continue;
12655 }
12656 if (counter < buffer_size) {
12657 buffer->set(counter, shared);
12658 }
12659 counter++;
12660 }
12661 return counter;
12662}
12663
12664// For a script finds all SharedFunctionInfo's in the heap that points
12665// to this script. Returns JSArray of SharedFunctionInfo wrapped
12666// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012667RUNTIME_FUNCTION(MaybeObject*,
12668 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012669 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012671 CONVERT_CHECKED(JSValue, script_value, args[0]);
12672
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012673
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012674 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12675
12676 const int kBufferSize = 32;
12677
12678 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012679 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012680 int number;
12681 {
12682 isolate->heap()->EnsureHeapIsIterable();
12683 AssertNoAllocation no_allocations;
12684 HeapIterator heap_iterator;
12685 Script* scr = *script;
12686 FixedArray* arr = *array;
12687 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12688 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012689 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012691 isolate->heap()->EnsureHeapIsIterable();
12692 AssertNoAllocation no_allocations;
12693 HeapIterator heap_iterator;
12694 Script* scr = *script;
12695 FixedArray* arr = *array;
12696 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012697 }
12698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012699 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012700 result->set_length(Smi::FromInt(number));
12701
12702 LiveEdit::WrapSharedFunctionInfos(result);
12703
12704 return *result;
12705}
12706
12707// For a script calculates compilation information about all its functions.
12708// The script source is explicitly specified by the second argument.
12709// The source of the actual script is not used, however it is important that
12710// all generated code keeps references to this particular instance of script.
12711// Returns a JSArray of compilation infos. The array is ordered so that
12712// each function with all its descendant is always stored in a continues range
12713// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012715 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717 CONVERT_CHECKED(JSValue, script, args[0]);
12718 CONVERT_ARG_CHECKED(String, source, 1);
12719 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12720
12721 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012723 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012724 return Failure::Exception();
12725 }
12726
12727 return result;
12728}
12729
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012730// Changes the source of the script to a new_source.
12731// If old_script_name is provided (i.e. is a String), also creates a copy of
12732// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012733RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012734 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012735 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012736 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12737 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012740 CONVERT_CHECKED(Script, original_script_pointer,
12741 original_script_value->value());
12742 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012744 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12745 new_source,
12746 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012747
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012748 if (old_script->IsScript()) {
12749 Handle<Script> script_handle(Script::cast(old_script));
12750 return *(GetScriptWrapper(script_handle));
12751 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012752 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012753 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012754}
12755
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012757RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012759 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012760 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12761 return LiveEdit::FunctionSourceUpdated(shared_info);
12762}
12763
12764
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012765// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012766RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012767 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012768 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012769 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12770 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12771
ager@chromium.orgac091b72010-05-05 07:34:42 +000012772 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012773}
12774
12775// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012776RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012777 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012778 HandleScope scope(isolate);
12779 Handle<Object> function_object(args[0], isolate);
12780 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012781
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012782 if (function_object->IsJSValue()) {
12783 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12784 if (script_object->IsJSValue()) {
12785 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012786 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012787 }
12788
12789 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12790 } else {
12791 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12792 // and we check it in this function.
12793 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012795 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012796}
12797
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012798
12799// In a code of a parent function replaces original function as embedded object
12800// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012801RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012802 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012804
12805 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12806 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12807 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12808
12809 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12810 subst_wrapper);
12811
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012812 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012813}
12814
12815
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012816// Updates positions of a shared function info (first parameter) according
12817// to script source change. Text change is described in second parameter as
12818// array of groups of 3 numbers:
12819// (change_begin, change_end, change_end_new_position).
12820// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012821RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012822 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012824 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12825 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12826
ager@chromium.orgac091b72010-05-05 07:34:42 +000012827 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012828}
12829
12830
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012831// For array of SharedFunctionInfo's (each wrapped in JSValue)
12832// checks that none of them have activations on stacks (of any thread).
12833// Returns array of the same length with corresponding results of
12834// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012835RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012836 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012837 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012838 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012839 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012840
ager@chromium.org357bf652010-04-12 11:30:10 +000012841 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012842}
12843
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012844// Compares 2 strings line-by-line, then token-wise and returns diff in form
12845// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12846// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012848 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012850 CONVERT_ARG_CHECKED(String, s1, 0);
12851 CONVERT_ARG_CHECKED(String, s2, 1);
12852
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012853 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012854}
12855
12856
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012857// A testing entry. Returns statement position which is the closest to
12858// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012860 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012861 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012862 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12863 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012865 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012866
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012867 if (code->kind() != Code::FUNCTION &&
12868 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012870 }
12871
12872 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012873 int closest_pc = 0;
12874 int distance = kMaxInt;
12875 while (!it.done()) {
12876 int statement_position = static_cast<int>(it.rinfo()->data());
12877 // Check if this break point is closer that what was previously found.
12878 if (source_position <= statement_position &&
12879 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012880 closest_pc =
12881 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012882 distance = statement_position - source_position;
12883 // Check whether we can't get any closer.
12884 if (distance == 0) break;
12885 }
12886 it.next();
12887 }
12888
12889 return Smi::FromInt(closest_pc);
12890}
12891
12892
ager@chromium.org357bf652010-04-12 11:30:10 +000012893// Calls specified function with or without entering the debugger.
12894// This is used in unit tests to run code as if debugger is entered or simply
12895// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012896RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012897 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012899 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12900 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12901
12902 Handle<Object> result;
12903 bool pending_exception;
12904 {
12905 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012907 &pending_exception);
12908 } else {
12909 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012911 &pending_exception);
12912 }
12913 }
12914 if (!pending_exception) {
12915 return *result;
12916 } else {
12917 return Failure::Exception();
12918 }
12919}
12920
12921
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012922// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012923RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012924 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012925 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012926 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12927 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012928 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012929}
12930
12931
12932// Performs a GC.
12933// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012934RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012935 isolate->heap()->CollectAllGarbage(true);
12936 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012937}
12938
12939
12940// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012941RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012942 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012943 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012944 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012945 }
12946 return Smi::FromInt(usage);
12947}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012948
12949
12950// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012951RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012952#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012953 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012954#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012955 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#endif
12957}
12958
12959
12960// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012961RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012962#ifdef LIVE_OBJECT_LIST
12963 return LiveObjectList::Capture();
12964#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012965 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966#endif
12967}
12968
12969
12970// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012971RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012972#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012973 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012974 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012975 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012977 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012978#endif
12979}
12980
12981
12982// Generates the response to a debugger request for a dump of the objects
12983// contained in the difference between the captured live object lists
12984// specified by id1 and id2.
12985// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12986// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012987RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988#ifdef LIVE_OBJECT_LIST
12989 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012990 CONVERT_SMI_ARG_CHECKED(id1, 0);
12991 CONVERT_SMI_ARG_CHECKED(id2, 1);
12992 CONVERT_SMI_ARG_CHECKED(start, 2);
12993 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012994 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12995 EnterDebugger enter_debugger;
12996 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12997#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012998 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012999#endif
13000}
13001
13002
13003// Gets the specified object as requested by the debugger.
13004// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013006#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013007 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013008 Object* result = LiveObjectList::GetObj(obj_id);
13009 return result;
13010#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013011 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012#endif
13013}
13014
13015
13016// Gets the obj id for the specified address if valid.
13017// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019#ifdef LIVE_OBJECT_LIST
13020 HandleScope scope;
13021 CONVERT_ARG_CHECKED(String, address, 0);
13022 Object* result = LiveObjectList::GetObjId(address);
13023 return result;
13024#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013025 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026#endif
13027}
13028
13029
13030// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013031RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013032#ifdef LIVE_OBJECT_LIST
13033 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013034 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013035 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13036 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13037 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13038 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13039 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13040
13041 Handle<JSObject> instance_filter;
13042 if (args[1]->IsJSObject()) {
13043 instance_filter = args.at<JSObject>(1);
13044 }
13045 bool verbose = false;
13046 if (args[2]->IsBoolean()) {
13047 verbose = args[2]->IsTrue();
13048 }
13049 int start = 0;
13050 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013051 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013052 }
13053 int limit = Smi::kMaxValue;
13054 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013055 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013056 }
13057
13058 return LiveObjectList::GetObjRetainers(obj_id,
13059 instance_filter,
13060 verbose,
13061 start,
13062 limit,
13063 filter_obj);
13064#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013065 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013066#endif
13067}
13068
13069
13070// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013071RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013072#ifdef LIVE_OBJECT_LIST
13073 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013074 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13075 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13077
13078 Handle<JSObject> instance_filter;
13079 if (args[2]->IsJSObject()) {
13080 instance_filter = args.at<JSObject>(2);
13081 }
13082
13083 Object* result =
13084 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13085 return result;
13086#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013087 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013088#endif
13089}
13090
13091
13092// Generates the response to a debugger request for a list of all
13093// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013094RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013095#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013096 CONVERT_SMI_ARG_CHECKED(start, 0);
13097 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013098 return LiveObjectList::Info(start, count);
13099#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013100 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013101#endif
13102}
13103
13104
13105// Gets a dump of the specified object as requested by the debugger.
13106// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013107RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013108#ifdef LIVE_OBJECT_LIST
13109 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013110 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013111 Object* result = LiveObjectList::PrintObj(obj_id);
13112 return result;
13113#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013114 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013115#endif
13116}
13117
13118
13119// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013120RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013121#ifdef LIVE_OBJECT_LIST
13122 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013123 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013124#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013125 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013126#endif
13127}
13128
13129
13130// Generates the response to a debugger request for a summary of the types
13131// of objects in the difference between the captured live object lists
13132// specified by id1 and id2.
13133// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13134// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013135RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013136#ifdef LIVE_OBJECT_LIST
13137 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013138 CONVERT_SMI_ARG_CHECKED(id1, 0);
13139 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013140 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13141
13142 EnterDebugger enter_debugger;
13143 return LiveObjectList::Summarize(id1, id2, filter_obj);
13144#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013145 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013146#endif
13147}
13148
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013149#endif // ENABLE_DEBUGGER_SUPPORT
13150
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013152RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013153 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013154 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013155 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013156}
13157
13158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013159RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013160 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013161 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013162 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013163}
13164
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013166// Finds the script object from the script data. NOTE: This operation uses
13167// heap traversal to find the function generated for the source position
13168// for the requested break point. For lazily compiled functions several heap
13169// traversals might be required rendering this operation as a rather slow
13170// operation. However for setting break points which is normally done through
13171// some kind of user interaction the performance is not crucial.
13172static Handle<Object> Runtime_GetScriptFromScriptName(
13173 Handle<String> script_name) {
13174 // Scan the heap for Script objects to find the script with the requested
13175 // script data.
13176 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013177 script_name->GetHeap()->EnsureHeapIsIterable();
13178 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013180 HeapObject* obj = NULL;
13181 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013182 // If a script is found check if it has the script data requested.
13183 if (obj->IsScript()) {
13184 if (Script::cast(obj)->name()->IsString()) {
13185 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13186 script = Handle<Script>(Script::cast(obj));
13187 }
13188 }
13189 }
13190 }
13191
13192 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013193 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013194
13195 // Return the script found.
13196 return GetScriptWrapper(script);
13197}
13198
13199
13200// Get the script object from script data. NOTE: Regarding performance
13201// see the NOTE for GetScriptFromScriptData.
13202// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013203RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013205
13206 ASSERT(args.length() == 1);
13207
13208 CONVERT_CHECKED(String, script_name, args[0]);
13209
13210 // Find the requested script.
13211 Handle<Object> result =
13212 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13213 return *result;
13214}
13215
13216
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013217// Determines whether the given stack frame should be displayed in
13218// a stack trace. The caller is the error constructor that asked
13219// for the stack trace to be collected. The first time a construct
13220// call to this function is encountered it is skipped. The seen_caller
13221// in/out parameter is used to remember if the caller has been seen
13222// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013223static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13224 Object* caller,
13225 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013226 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013227 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013228 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013229 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013230 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13231 Object* raw_fun = frame->function();
13232 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013233 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013234 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013236 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013237 *seen_caller = true;
13238 return false;
13239 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013240 // Skip all frames until we've seen the caller.
13241 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013242 // Also, skip non-visible built-in functions and any call with the builtins
13243 // object as receiver, so as to not reveal either the builtins object or
13244 // an internal function.
13245 // The --builtins-in-stack-traces command line flag allows including
13246 // internal call sites in the stack trace for debugging purposes.
13247 if (!FLAG_builtins_in_stack_traces) {
13248 JSFunction* fun = JSFunction::cast(raw_fun);
13249 if (frame->receiver()->IsJSBuiltinsObject() ||
13250 (fun->IsBuiltin() && !fun->shared()->native())) {
13251 return false;
13252 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013253 }
13254 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013255}
13256
13257
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013258// Collect the raw data for a stack trace. Returns an array of 4
13259// element segments each containing a receiver, function, code and
13260// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013261RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013262 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013263 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013264 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013266 HandleScope scope(isolate);
13267 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013268
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013269 limit = Max(limit, 0); // Ensure that limit is not negative.
13270 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013271 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013272 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013273
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013274 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013275 // If the caller parameter is a function we skip frames until we're
13276 // under it before starting to collect.
13277 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013278 int cursor = 0;
13279 int frames_seen = 0;
13280 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013281 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013282 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013283 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013284 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013285 // Set initial size to the maximum inlining level + 1 for the outermost
13286 // function.
13287 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013288 frame->Summarize(&frames);
13289 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013290 if (cursor + 4 > elements->length()) {
13291 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13292 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013293 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013294 for (int i = 0; i < cursor; i++) {
13295 new_elements->set(i, elements->get(i));
13296 }
13297 elements = new_elements;
13298 }
13299 ASSERT(cursor + 4 <= elements->length());
13300
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013301 Handle<Object> recv = frames[i].receiver();
13302 Handle<JSFunction> fun = frames[i].function();
13303 Handle<Code> code = frames[i].code();
13304 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013305 elements->set(cursor++, *recv);
13306 elements->set(cursor++, *fun);
13307 elements->set(cursor++, *code);
13308 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013309 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013310 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013311 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013312 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013313 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013314 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013315 return *result;
13316}
13317
13318
ager@chromium.org3811b432009-10-28 14:53:37 +000013319// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013320RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013321 ASSERT_EQ(args.length(), 0);
13322
13323 NoHandleAllocation ha;
13324
13325 const char* version_string = v8::V8::GetVersion();
13326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013327 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13328 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013329}
13330
13331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013332RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013333 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013334 OS::PrintError("abort: %s\n",
13335 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013336 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013337 OS::Abort();
13338 UNREACHABLE();
13339 return NULL;
13340}
13341
13342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013343RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013344 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013345 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013346 Object* key = args[1];
13347
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013348 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013349 Object* o = cache->get(finger_index);
13350 if (o == key) {
13351 // The fastest case: hit the same place again.
13352 return cache->get(finger_index + 1);
13353 }
13354
13355 for (int i = finger_index - 2;
13356 i >= JSFunctionResultCache::kEntriesIndex;
13357 i -= 2) {
13358 o = cache->get(i);
13359 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013360 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013361 return cache->get(i + 1);
13362 }
13363 }
13364
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013365 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013366 ASSERT(size <= cache->length());
13367
13368 for (int i = size - 2; i > finger_index; i -= 2) {
13369 o = cache->get(i);
13370 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013371 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013372 return cache->get(i + 1);
13373 }
13374 }
13375
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013376 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013377 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013378
13379 Handle<JSFunctionResultCache> cache_handle(cache);
13380 Handle<Object> key_handle(key);
13381 Handle<Object> value;
13382 {
13383 Handle<JSFunction> factory(JSFunction::cast(
13384 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13385 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013386 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013387 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013388 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013389 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013390 value = Execution::Call(factory,
13391 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013392 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013393 argv,
13394 &pending_exception);
13395 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013396 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013397
13398#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013399 if (FLAG_verify_heap) {
13400 cache_handle->JSFunctionResultCacheVerify();
13401 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013402#endif
13403
13404 // Function invocation may have cleared the cache. Reread all the data.
13405 finger_index = cache_handle->finger_index();
13406 size = cache_handle->size();
13407
13408 // If we have spare room, put new data into it, otherwise evict post finger
13409 // entry which is likely to be the least recently used.
13410 int index = -1;
13411 if (size < cache_handle->length()) {
13412 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13413 index = size;
13414 } else {
13415 index = finger_index + JSFunctionResultCache::kEntrySize;
13416 if (index == cache_handle->length()) {
13417 index = JSFunctionResultCache::kEntriesIndex;
13418 }
13419 }
13420
13421 ASSERT(index % 2 == 0);
13422 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13423 ASSERT(index < cache_handle->length());
13424
13425 cache_handle->set(index, *key_handle);
13426 cache_handle->set(index + 1, *value);
13427 cache_handle->set_finger_index(index);
13428
13429#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013430 if (FLAG_verify_heap) {
13431 cache_handle->JSFunctionResultCacheVerify();
13432 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013433#endif
13434
13435 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013436}
13437
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013439RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013440 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013441 CONVERT_ARG_CHECKED(String, type, 0);
13442 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013443 return *isolate->factory()->NewJSMessageObject(
13444 type,
13445 arguments,
13446 0,
13447 0,
13448 isolate->factory()->undefined_value(),
13449 isolate->factory()->undefined_value(),
13450 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013451}
13452
13453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013454RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013455 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13456 return message->type();
13457}
13458
13459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013460RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013461 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13462 return message->arguments();
13463}
13464
13465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013466RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013467 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13468 return Smi::FromInt(message->start_position());
13469}
13470
13471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013472RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013473 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13474 return message->script();
13475}
13476
13477
kasper.lund44510672008-07-25 07:37:58 +000013478#ifdef DEBUG
13479// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13480// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013481RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013482 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013483 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013484#define COUNT_ENTRY(Name, argc, ressize) + 1
13485 int entry_count = 0
13486 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13487 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13488 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13489#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013490 Factory* factory = isolate->factory();
13491 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013492 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013493 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013494#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013495 { \
13496 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013497 Handle<String> name; \
13498 /* Inline runtime functions have an underscore in front of the name. */ \
13499 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013500 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013501 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13502 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013503 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013504 Vector<const char>(#Name, StrLength(#Name))); \
13505 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013506 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013507 pair_elements->set(0, *name); \
13508 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013509 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013510 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013511 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013512 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013513 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013514 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013515 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013516 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013517#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013518 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013519 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013520 return *result;
13521}
kasper.lund44510672008-07-25 07:37:58 +000013522#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013523
13524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013525RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013526 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013527 CONVERT_CHECKED(String, format, args[0]);
13528 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013529 String::FlatContent format_content = format->GetFlatContent();
13530 RUNTIME_ASSERT(format_content.IsAscii());
13531 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013532 LOGGER->LogRuntime(chars, elms);
13533 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013534}
13535
13536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013537RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013538 UNREACHABLE(); // implemented as macro in the parser
13539 return NULL;
13540}
13541
13542
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013543#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13544 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13545 CONVERT_CHECKED(JSObject, obj, args[0]); \
13546 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13547 }
13548
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013549ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013550ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13551ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13552ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13553ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13554ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13555ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13556ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13557ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13558ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13559ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13560ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13561ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13562ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13563
13564#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13565
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013566
13567RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13568 ASSERT(args.length() == 2);
13569 CONVERT_CHECKED(JSObject, obj1, args[0]);
13570 CONVERT_CHECKED(JSObject, obj2, args[1]);
13571 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13572}
13573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013574// ----------------------------------------------------------------------------
13575// Implementation of Runtime
13576
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013577#define F(name, number_of_args, result_size) \
13578 { Runtime::k##name, Runtime::RUNTIME, #name, \
13579 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013580
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013581
13582#define I(name, number_of_args, result_size) \
13583 { Runtime::kInline##name, Runtime::INLINE, \
13584 "_" #name, NULL, number_of_args, result_size },
13585
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013586static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013587 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013588 INLINE_FUNCTION_LIST(I)
13589 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013590};
13591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013593MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13594 Object* dictionary) {
13595 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013596 ASSERT(dictionary != NULL);
13597 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13598 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013599 Object* name_symbol;
13600 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013601 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013602 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13603 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013604 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013605 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13606 String::cast(name_symbol),
13607 Smi::FromInt(i),
13608 PropertyDetails(NONE, NORMAL));
13609 if (!maybe_dictionary->ToObject(&dictionary)) {
13610 // Non-recoverable failure. Calling code must restart heap
13611 // initialization.
13612 return maybe_dictionary;
13613 }
13614 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013615 }
13616 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013617}
13618
13619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013620const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13621 Heap* heap = name->GetHeap();
13622 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013623 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013624 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013625 int function_index = Smi::cast(smi_index)->value();
13626 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013627 }
13628 return NULL;
13629}
13630
13631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013632const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013633 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13634}
13635
13636
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013637void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013638 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013639 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013640 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013641 if (isolate->heap()->new_space()->AddFreshPage()) {
13642 return;
13643 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013644 // Try to do a garbage collection; ignore it if it fails. The C
13645 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013646 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013647 } else {
13648 // Handle last resort GC and make sure to allow future allocations
13649 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013650 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013651 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013653}
13654
13655
13656} } // namespace v8::internal