blob: 811d72d91d6832645f74579661a4ef4601671122 [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: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000231 NumberDictionary* element_dictionary = copy->element_dictionary();
232 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.
358 if (!should_have_fast_elements) NormalizeElements(boilerplate);
359
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.
368 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
369 }
370
371 for (int index = 0; index < length; index +=2) {
372 Handle<Object> key(constant_properties->get(index+0), isolate);
373 Handle<Object> value(constant_properties->get(index+1), isolate);
374 if (value->IsFixedArray()) {
375 // The value contains the constant_properties of a
376 // simple object or array literal.
377 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
378 value = CreateLiteralBoilerplate(isolate, literals, array);
379 if (value.is_null()) return value;
380 }
381 Handle<Object> result;
382 uint32_t element_index = 0;
383 if (key->IsSymbol()) {
384 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
385 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000386 result = SetOwnElement(boilerplate,
387 element_index,
388 value,
389 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<String> name(String::cast(*key));
392 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000393 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
394 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 } else if (key->ToArrayIndex(&element_index)) {
397 // Array index (uint32).
398 result = SetOwnElement(boilerplate,
399 element_index,
400 value,
401 kNonStrictMode);
402 } else {
403 // Non-uint32 number.
404 ASSERT(key->IsNumber());
405 double num = key->Number();
406 char arr[100];
407 Vector<char> buffer(arr, ARRAY_SIZE(arr));
408 const char* str = DoubleToCString(num, buffer);
409 Handle<String> name =
410 isolate->factory()->NewStringFromAscii(CStrVector(str));
411 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
412 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 // If setting the property on the boilerplate throws an
415 // exception, the exception is converted to an empty handle in
416 // the handle based operations. In that case, we need to
417 // convert back to an exception.
418 if (result.is_null()) return result;
419 }
420
421 // Transform to fast properties if necessary. For object literals with
422 // containing function literals we defer this operation until after all
423 // computed properties have been assigned so that we can generate
424 // constant function properties.
425 if (should_transform && !has_function_literal) {
426 TransformToFastProperties(boilerplate,
427 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000431}
432
433
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000434static const int kSmiOnlyLiteralMinimumLength = 1024;
435
436
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000437// static
438Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000540 return Runtime::CreateArrayLiteralBoilerplate(
541 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000542 default:
543 UNREACHABLE();
544 return Handle<Object>::null();
545 }
546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
557 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000558
559 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> boilerplate(literals->get(literals_index), isolate);
561 if (*boilerplate == isolate->heap()->undefined_value()) {
562 boilerplate = CreateObjectLiteralBoilerplate(isolate,
563 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000564 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 should_have_fast_elements,
566 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567 if (boilerplate.is_null()) return Failure::Exception();
568 // Update the functions literal and return the boilerplate.
569 literals->set(literals_index, *boilerplate);
570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572}
573
574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000575RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000577 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000581 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
583 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584
585 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 Handle<Object> boilerplate(literals->get(literals_index), isolate);
587 if (*boilerplate == isolate->heap()->undefined_value()) {
588 boilerplate = CreateObjectLiteralBoilerplate(isolate,
589 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000590 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 should_have_fast_elements,
592 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000598}
599
600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000601RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603 ASSERT(args.length() == 3);
604 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000605 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000606 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
607
608 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 Handle<Object> boilerplate(literals->get(literals_index), isolate);
610 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000611 boilerplate =
612 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000613 if (boilerplate.is_null()) return Failure::Exception();
614 // Update the functions literal and return the boilerplate.
615 literals->set(literals_index, *boilerplate);
616 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000618}
619
620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000621RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 ASSERT(args.length() == 3);
624 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000625 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000626 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
627
628 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<Object> boilerplate(literals->get(literals_index), isolate);
630 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000631 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000632 boilerplate =
633 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000634 if (boilerplate.is_null()) return Failure::Exception();
635 // Update the functions literal and return the boilerplate.
636 literals->set(literals_index, *boilerplate);
637 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000638 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000640 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643}
644
645
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
647 ASSERT(args.length() == 2);
648 Object* handler = args[0];
649 Object* prototype = args[1];
650 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000652 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
653}
654
655
lrn@chromium.org34e60782011-09-15 07:25:40 +0000656RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
657 ASSERT(args.length() == 4);
658 Object* handler = args[0];
659 Object* call_trap = args[1];
660 Object* construct_trap = args[2];
661 Object* prototype = args[3];
662 Object* used_prototype =
663 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
664 return isolate->heap()->AllocateJSFunctionProxy(
665 handler, call_trap, construct_trap, used_prototype);
666}
667
668
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
670 ASSERT(args.length() == 1);
671 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000672 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000673}
674
675
lrn@chromium.org34e60782011-09-15 07:25:40 +0000676RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
679 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
680}
681
682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
684 ASSERT(args.length() == 1);
685 CONVERT_CHECKED(JSProxy, proxy, args[0]);
686 return proxy->handler();
687}
688
689
lrn@chromium.org34e60782011-09-15 07:25:40 +0000690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
691 ASSERT(args.length() == 1);
692 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
693 return proxy->call_trap();
694}
695
696
697RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
698 ASSERT(args.length() == 1);
699 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
700 return proxy->construct_trap();
701}
702
703
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
705 ASSERT(args.length() == 1);
706 CONVERT_CHECKED(JSProxy, proxy, args[0]);
707 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000708 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000709}
710
711
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000712RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
713 HandleScope scope(isolate);
714 ASSERT(args.length() == 1);
715 CONVERT_ARG_CHECKED(JSSet, holder, 0);
716 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
717 holder->set_table(*table);
718 return *holder;
719}
720
721
722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
723 HandleScope scope(isolate);
724 ASSERT(args.length() == 2);
725 CONVERT_ARG_CHECKED(JSSet, holder, 0);
726 Handle<Object> key(args[1]);
727 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
728 table = ObjectHashSetAdd(table, key);
729 holder->set_table(*table);
730 return isolate->heap()->undefined_symbol();
731}
732
733
734RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
735 HandleScope scope(isolate);
736 ASSERT(args.length() == 2);
737 CONVERT_ARG_CHECKED(JSSet, holder, 0);
738 Handle<Object> key(args[1]);
739 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
740 return isolate->heap()->ToBoolean(table->Contains(*key));
741}
742
743
744RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
745 HandleScope scope(isolate);
746 ASSERT(args.length() == 2);
747 CONVERT_ARG_CHECKED(JSSet, holder, 0);
748 Handle<Object> key(args[1]);
749 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
750 table = ObjectHashSetRemove(table, key);
751 holder->set_table(*table);
752 return isolate->heap()->undefined_symbol();
753}
754
755
756RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
757 HandleScope scope(isolate);
758 ASSERT(args.length() == 1);
759 CONVERT_ARG_CHECKED(JSMap, holder, 0);
760 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
761 holder->set_table(*table);
762 return *holder;
763}
764
765
766RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
767 HandleScope scope(isolate);
768 ASSERT(args.length() == 2);
769 CONVERT_ARG_CHECKED(JSMap, holder, 0);
770 Handle<Object> key(args[1]);
771 return ObjectHashTable::cast(holder->table())->Lookup(*key);
772}
773
774
775RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
776 HandleScope scope(isolate);
777 ASSERT(args.length() == 3);
778 CONVERT_ARG_CHECKED(JSMap, holder, 0);
779 Handle<Object> key(args[1]);
780 Handle<Object> value(args[2]);
781 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
782 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
783 holder->set_table(*new_table);
784 return *value;
785}
786
787
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000788RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
789 HandleScope scope(isolate);
790 ASSERT(args.length() == 1);
791 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
792 ASSERT(weakmap->map()->inobject_properties() == 0);
793 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
794 weakmap->set_table(*table);
795 weakmap->set_next(Smi::FromInt(0));
796 return *weakmap;
797}
798
799
800RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
801 NoHandleAllocation ha;
802 ASSERT(args.length() == 2);
803 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
805 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806}
807
808
809RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
810 HandleScope scope(isolate);
811 ASSERT(args.length() == 3);
812 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000814 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000815 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000816 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
817 weakmap->set_table(*new_table);
818 return *value;
819}
820
821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000822RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 NoHandleAllocation ha;
824 ASSERT(args.length() == 1);
825 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000826 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 return JSObject::cast(obj)->class_name();
828}
829
ager@chromium.org7c537e22008-10-16 08:43:32 +0000830
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
832 NoHandleAllocation ha;
833 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000834 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
835 Object* obj = input_obj;
836 // We don't expect access checks to be needed on JSProxy objects.
837 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000838 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000839 if (obj->IsAccessCheckNeeded() &&
840 !isolate->MayNamedAccess(JSObject::cast(obj),
841 isolate->heap()->Proto_symbol(),
842 v8::ACCESS_GET)) {
843 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
844 return isolate->heap()->undefined_value();
845 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000846 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000847 } while (obj->IsJSObject() &&
848 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849 return obj;
850}
851
852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000853RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 NoHandleAllocation ha;
855 ASSERT(args.length() == 2);
856 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
857 Object* O = args[0];
858 Object* V = args[1];
859 while (true) {
860 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 if (prototype->IsNull()) return isolate->heap()->false_value();
862 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 V = prototype;
864 }
865}
866
867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000868RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000870 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000871 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873}
874
875
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000876// Recursively traverses hidden prototypes if property is not found
877static void GetOwnPropertyImplementation(JSObject* obj,
878 String* name,
879 LookupResult* result) {
880 obj->LocalLookupRealNamedProperty(name, result);
881
882 if (!result->IsProperty()) {
883 Object* proto = obj->GetPrototype();
884 if (proto->IsJSObject() &&
885 JSObject::cast(proto)->map()->is_hidden_prototype())
886 GetOwnPropertyImplementation(JSObject::cast(proto),
887 name, result);
888 }
889}
890
891
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892static bool CheckAccessException(LookupResult* result,
893 v8::AccessType access_type) {
894 if (result->type() == CALLBACKS) {
895 Object* callback = result->GetCallbackObject();
896 if (callback->IsAccessorInfo()) {
897 AccessorInfo* info = AccessorInfo::cast(callback);
898 bool can_access =
899 (access_type == v8::ACCESS_HAS &&
900 (info->all_can_read() || info->all_can_write())) ||
901 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
902 (access_type == v8::ACCESS_SET && info->all_can_write());
903 return can_access;
904 }
905 }
906
907 return false;
908}
909
910
911static bool CheckAccess(JSObject* obj,
912 String* name,
913 LookupResult* result,
914 v8::AccessType access_type) {
915 ASSERT(result->IsProperty());
916
917 JSObject* holder = result->holder();
918 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000920 while (true) {
921 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000923 // Access check callback denied the access, but some properties
924 // can have a special permissions which override callbacks descision
925 // (currently see v8::AccessControl).
926 break;
927 }
928
929 if (current == holder) {
930 return true;
931 }
932
933 current = JSObject::cast(current->GetPrototype());
934 }
935
936 // API callbacks can have per callback access exceptions.
937 switch (result->type()) {
938 case CALLBACKS: {
939 if (CheckAccessException(result, access_type)) {
940 return true;
941 }
942 break;
943 }
944 case INTERCEPTOR: {
945 // If the object has an interceptor, try real named properties.
946 // Overwrite the result to fetch the correct property later.
947 holder->LookupRealNamedProperty(name, result);
948 if (result->IsProperty()) {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 }
953 break;
954 }
955 default:
956 break;
957 }
958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000960 return false;
961}
962
963
964// TODO(1095): we should traverse hidden prototype hierachy as well.
965static bool CheckElementAccess(JSObject* obj,
966 uint32_t index,
967 v8::AccessType access_type) {
968 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971 }
972
973 return true;
974}
975
976
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000977// Enumerator used as indices into the array returned from GetOwnProperty
978enum PropertyDescriptorIndices {
979 IS_ACCESSOR_INDEX,
980 VALUE_INDEX,
981 GETTER_INDEX,
982 SETTER_INDEX,
983 WRITABLE_INDEX,
984 ENUMERABLE_INDEX,
985 CONFIGURABLE_INDEX,
986 DESCRIPTOR_SIZE
987};
988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000989// Returns an array with the property description:
990// if args[1] is not a property on args[0]
991// returns undefined
992// if args[1] is a data property on args[0]
993// [false, value, Writeable, Enumerable, Configurable]
994// if args[1] is an accessor on args[0]
995// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000997 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 Heap* heap = isolate->heap();
999 HandleScope scope(isolate);
1000 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1001 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001002 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001003 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1004 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001005
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001006 // This could be an element.
1007 uint32_t index;
1008 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 switch (obj->HasLocalElement(index)) {
1010 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001012
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001013 case JSObject::STRING_CHARACTER_ELEMENT: {
1014 // Special handling of string objects according to ECMAScript 5
1015 // 15.5.5.2. Note that this might be a string object with elements
1016 // other than the actual string value. This is covered by the
1017 // subsequent cases.
1018 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1019 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001020 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 elms->set(WRITABLE_INDEX, heap->false_value());
1025 elms->set(ENUMERABLE_INDEX, heap->false_value());
1026 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 return *desc;
1028 }
1029
1030 case JSObject::INTERCEPTED_ELEMENT:
1031 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001035 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 elms->set(WRITABLE_INDEX, heap->true_value());
1037 elms->set(ENUMERABLE_INDEX, heap->true_value());
1038 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001039 return *desc;
1040 }
1041
1042 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 Handle<JSObject> holder = obj;
1044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 holder = Handle<JSObject>(JSObject::cast(proto));
1049 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 FixedArray* elements = FixedArray::cast(holder->elements());
1051 NumberDictionary* dictionary = NULL;
1052 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1053 dictionary = NumberDictionary::cast(elements->get(1));
1054 } else {
1055 dictionary = NumberDictionary::cast(elements);
1056 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 int entry = dictionary->FindEntry(index);
1058 ASSERT(entry != NumberDictionary::kNotFound);
1059 PropertyDetails details = dictionary->DetailsAt(entry);
1060 switch (details.type()) {
1061 case CALLBACKS: {
1062 // This is an accessor property with getter and/or setter.
1063 FixedArray* callbacks =
1064 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001066 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1067 elms->set(GETTER_INDEX, callbacks->get(0));
1068 }
1069 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1070 elms->set(SETTER_INDEX, callbacks->get(1));
1071 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001072 break;
1073 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001077 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001078 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001079 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001082 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 default:
1084 UNREACHABLE();
1085 break;
1086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1088 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 return *desc;
1090 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001091 }
1092 }
1093
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001094 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001095 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001097 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001099 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001100
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001101 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001103 }
1104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001107
1108 bool is_js_accessor = (result.type() == CALLBACKS) &&
1109 (result.GetCallbackObject()->IsFixedArray());
1110
1111 if (is_js_accessor) {
1112 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114
1115 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1116 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1117 elms->set(GETTER_INDEX, structure->get(0));
1118 }
1119 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1120 elms->set(SETTER_INDEX, structure->get(1));
1121 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1124 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 PropertyAttributes attrs;
1127 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001128 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001129 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1130 if (!maybe_value->ToObject(&value)) return maybe_value;
1131 }
1132 elms->set(VALUE_INDEX, value);
1133 }
1134
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001135 return *desc;
1136}
1137
1138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001139RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001140 ASSERT(args.length() == 1);
1141 CONVERT_CHECKED(JSObject, obj, args[0]);
1142 return obj->PreventExtensions();
1143}
1144
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001146RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001147 ASSERT(args.length() == 1);
1148 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001149 if (obj->IsJSGlobalProxy()) {
1150 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001152 ASSERT(proto->IsJSGlobalObject());
1153 obj = JSObject::cast(proto);
1154 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001155 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156}
1157
1158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001159RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001162 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1163 CONVERT_ARG_CHECKED(String, pattern, 1);
1164 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001165 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1166 if (result.is_null()) return Failure::Exception();
1167 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168}
1169
1170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001171RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001174 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001175 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001179RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 ASSERT(args.length() == 1);
1181 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001182 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 ASSERT(args.length() == 2);
1189 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001191 int index = field->value();
1192 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1193 InstanceType type = templ->map()->instance_type();
1194 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1195 type == OBJECT_TEMPLATE_INFO_TYPE);
1196 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001197 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001198 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1199 } else {
1200 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1201 }
1202 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203}
1204
1205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001206RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001207 ASSERT(args.length() == 1);
1208 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001209 Map* old_map = object->map();
1210 bool needs_access_checks = old_map->is_access_check_needed();
1211 if (needs_access_checks) {
1212 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001213 Object* new_map;
1214 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1215 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1216 }
ager@chromium.org32912102009-01-16 10:38:43 +00001217
1218 Map::cast(new_map)->set_is_access_check_needed(false);
1219 object->set_map(Map::cast(new_map));
1220 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001221 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222}
1223
1224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001225RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001226 ASSERT(args.length() == 1);
1227 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001228 Map* old_map = object->map();
1229 if (!old_map->is_access_check_needed()) {
1230 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001231 Object* new_map;
1232 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1233 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 }
ager@chromium.org32912102009-01-16 10:38:43 +00001235
1236 Map::cast(new_map)->set_is_access_check_needed(true);
1237 object->set_map(Map::cast(new_map));
1238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001240}
1241
1242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243static Failure* ThrowRedeclarationError(Isolate* isolate,
1244 const char* type,
1245 Handle<String> name) {
1246 HandleScope scope(isolate);
1247 Handle<Object> type_handle =
1248 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 Handle<Object> args[2] = { type_handle, name };
1250 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1252 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253}
1254
1255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001256RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001257 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 HandleScope scope(isolate);
1259 Handle<GlobalObject> global = Handle<GlobalObject>(
1260 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
ager@chromium.org3811b432009-10-28 14:53:37 +00001262 Handle<Context> context = args.at<Context>(0);
1263 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001264 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 // Traverse the name/value pairs and set the properties.
1267 int length = pairs->length();
1268 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001271 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
1273 // We have to declare a global const property. To capture we only
1274 // assign to it when evaluating the assignment for "const x =
1275 // <expr>" the initial value is the hole.
1276 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001277 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 if (value->IsUndefined() || is_const_property) {
1279 // Lookup the property in the global object, and don't set the
1280 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001281 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 global->Lookup(*name, &lookup);
1283 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001284 // We found an existing property. Unless it was an interceptor
1285 // that claims the property is absent, skip this declaration.
1286 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 continue;
1288 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001289 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1290 if (attributes != ABSENT) {
1291 continue;
1292 }
1293 // Fall-through and introduce the absent property by using
1294 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 }
1296 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001297 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001299 Handle<SharedFunctionInfo> shared =
1300 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1303 context,
1304 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 value = function;
1306 }
1307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001308 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 global->LocalLookup(*name, &lookup);
1310
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001311 // Compute the property attributes. According to ECMA-262, section
1312 // 13, page 71, the property must be read-only and
1313 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1314 // property as read-only, so we don't either.
1315 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001316 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001317 attr |= DONT_DELETE;
1318 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001319 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001320 if (is_const_property || (is_native && is_function_declaration)) {
1321 attr |= READ_ONLY;
1322 }
1323
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 // Safari does not allow the invocation of callback setters for
1325 // function declarations. To mimic this behavior, we do not allow
1326 // the invocation of setters for function values. This makes a
1327 // difference for global functions with the same names as event
1328 // handlers such as "function onload() {}". Firefox does call the
1329 // onload setter in those case and Safari does not. We follow
1330 // Safari for compatibility.
1331 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001332 // Do not change DONT_DELETE to false from true.
1333 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001334 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001335 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 RETURN_IF_EMPTY_HANDLE(isolate,
1339 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 name,
1341 value,
1342 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001344 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1345 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1346 ? kNonStrictMode : kStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 RETURN_IF_EMPTY_HANDLE(isolate,
1348 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001349 name,
1350 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001351 static_cast<PropertyAttributes>(attr),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001352 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
1354 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 ASSERT(!isolate->has_pending_exception());
1357 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358}
1359
1360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001361RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001363 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 // Declarations are always made in a function or global context. In the
1366 // case of eval code, the context passed is the context of the caller,
1367 // which may be some nested context and not the declaration context.
1368 RUNTIME_ASSERT(args[0]->IsContext());
1369 Handle<Context> context(Context::cast(args[0])->declaration_context());
1370
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001372 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001373 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 int index;
1377 PropertyAttributes attributes;
1378 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001379 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001380 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001381 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
1383 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1386 // Functions are not read-only.
1387 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1388 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001389 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 }
1391
1392 // Initialize it if necessary.
1393 if (*initial_value != NULL) {
1394 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 ASSERT(holder.is_identical_to(context));
1396 if (((attributes & READ_ONLY) == 0) ||
1397 context->get(index)->IsTheHole()) {
1398 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 // Slow case: The property is in the context extension object of a
1402 // function context or the global object of a global context.
1403 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001404 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001406 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 }
1408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 // "declared" in the function context's extension context or as a
1413 // property of the the global object.
1414 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001415 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001416 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001417 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 // Context extension objects are allocated lazily.
1419 ASSERT(context->IsFunctionContext());
1420 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001423 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // Declare the property by setting it to the initial value if provided,
1427 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1428 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001431 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001432 // Declaring a const context slot is a conflicting declaration if
1433 // there is a callback with that name in a prototype. It is
1434 // allowed to introduce const variables in
1435 // JSContextExtensionObjects. They are treated specially in
1436 // SetProperty and no setters are invoked for those since they are
1437 // not real JSObjects.
1438 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001440 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001441 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001444 }
1445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001448 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001449 }
1450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452}
1453
1454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001455RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001457 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001458 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001459 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Determine if we need to assign to the variable if it already
1462 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1464 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465
1466 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001468 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001469 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1470 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1471 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
1473 // According to ECMA-262, section 12.2, page 62, the property must
1474 // not be deletable.
1475 PropertyAttributes attributes = DONT_DELETE;
1476
1477 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001478 // there, there is a property with this name in the prototype chain.
1479 // We follow Safari and Firefox behavior and only set the property
1480 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001481 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001482 // Note that objects can have hidden prototypes, so we need to traverse
1483 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001484 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001485 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 while (object->IsJSObject() &&
1487 JSObject::cast(object)->map()->is_hidden_prototype()) {
1488 JSObject* raw_holder = JSObject::cast(object);
1489 raw_holder->LocalLookup(*name, &lookup);
1490 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1491 HandleScope handle_scope(isolate);
1492 Handle<JSObject> holder(raw_holder);
1493 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1494 // Update the raw pointer in case it's changed due to GC.
1495 raw_holder = *holder;
1496 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1497 // Found an interceptor that's not read only.
1498 if (assign) {
1499 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001500 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 } else {
1502 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001503 }
1504 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001511 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001512 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515}
1516
1517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001518RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 // All constants are declared with an initial value. The name
1520 // of the constant is the first argument and the initial value
1521 // is the second.
1522 RUNTIME_ASSERT(args.length() == 2);
1523 CONVERT_ARG_CHECKED(String, name, 0);
1524 Handle<Object> value = args.at<Object>(1);
1525
1526 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528
1529 // According to ECMA-262, section 12.2, page 62, the property must
1530 // not be deletable. Since it's a const, it must be READ_ONLY too.
1531 PropertyAttributes attributes =
1532 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1533
1534 // Lookup the property locally in the global object. If it isn't
1535 // there, we add the property and take special precautions to always
1536 // add it as a local property even in case of callbacks in the
1537 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001538 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001539 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 global->LocalLookup(*name, &lookup);
1541 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001542 return global->SetLocalPropertyIgnoreAttributes(*name,
1543 *value,
1544 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 }
1546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 HandleScope handle_scope(isolate);
1551 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001553 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 // property through an interceptor and only do it if it's
1555 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 RETURN_IF_EMPTY_HANDLE(isolate,
1558 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 name,
1560 value,
1561 attributes,
1562 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 return *value;
1564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 // constant. For now, we determine this by checking if the
1568 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 PropertyType type = lookup.type();
1571 if (type == FIELD) {
1572 FixedArray* properties = global->properties();
1573 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 properties->set(index, *value);
1576 }
1577 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001578 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1579 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001580 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
1582 } else {
1583 // Ignore re-initialization of constants that have already been
1584 // assigned a function value.
1585 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1586 }
1587
1588 // Use the set value as the result of the operation.
1589 return *value;
1590}
1591
1592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001593RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(args.length() == 3);
1596
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001600 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001601 RUNTIME_ASSERT(args[1]->IsContext());
1602 Handle<Context> context(Context::cast(args[1])->declaration_context());
1603
1604 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
1606 int index;
1607 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001608 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001609 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001610 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001611 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 ASSERT(holder->IsContext());
1615 // Property was found in a context. Perform the assignment if we
1616 // found some non-constant or an uninitialized constant.
1617 Handle<Context> context = Handle<Context>::cast(holder);
1618 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1619 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 }
1621 return *value;
1622 }
1623
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 // The property could not be found, we introduce it as a property of the
1625 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001627 Handle<JSObject> global = Handle<JSObject>(
1628 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 // Strict mode not needed (const disallowed in strict mode).
1630 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001632 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 return *value;
1634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 // The property was present in some function's context extension object,
1637 // as a property on the subject of a with, or as a property of the global
1638 // object.
1639 //
1640 // In most situations, eval-introduced consts should still be present in
1641 // the context extension object. However, because declaration and
1642 // initialization are separate, the property might have been deleted
1643 // before we reach the initialization point.
1644 //
1645 // Example:
1646 //
1647 // function f() { eval("delete x; const x;"); }
1648 //
1649 // In that case, the initialization behaves like a normal assignment.
1650 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 if (*object == context->extension()) {
1653 // This is the property that was introduced by the const declaration.
1654 // Set it if it hasn't been set before. NOTE: We cannot use
1655 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001658 ASSERT(lookup.IsProperty()); // the property was declared
1659 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1660
1661 PropertyType type = lookup.type();
1662 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 int index = lookup.GetFieldIndex();
1665 if (properties->get(index)->IsTheHole()) {
1666 properties->set(index, *value);
1667 }
1668 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001669 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1670 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001671 }
1672 } else {
1673 // We should not reach here. Any real, named property should be
1674 // either a field or a dictionary slot.
1675 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 }
1677 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001678 // The property was found on some other object. Set it if it is not a
1679 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001680 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001681 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001682 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001683 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 return *value;
1689}
1690
1691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692RUNTIME_FUNCTION(MaybeObject*,
1693 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001695 ASSERT(args.length() == 2);
1696 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001698 if (object->HasFastProperties()) {
1699 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1700 }
1701 return *object;
1702}
1703
1704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001705RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001707 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001708 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1709 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001712 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001713 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001714 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001715 RUNTIME_ASSERT(index >= 0);
1716 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 Handle<Object> result = RegExpImpl::Exec(regexp,
1719 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001720 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001722 if (result.is_null()) return Failure::Exception();
1723 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724}
1725
1726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001727RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001729 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001730 if (elements_count < 0 ||
1731 elements_count > FixedArray::kMaxLength ||
1732 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 Object* new_object;
1736 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1739 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1742 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1744 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 {
1746 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 }
1751 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001753 array->set_elements(elements);
1754 array->set_length(Smi::FromInt(elements_count));
1755 // Write in-object properties after the length of the array.
1756 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1757 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1758 return array;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001763 AssertNoAllocation no_alloc;
1764 ASSERT(args.length() == 5);
1765 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1766 CONVERT_CHECKED(String, source, args[1]);
1767
1768 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776
1777 Map* map = regexp->map();
1778 Object* constructor = map->constructor();
1779 if (constructor->IsJSFunction() &&
1780 JSFunction::cast(constructor)->initial_map() == map) {
1781 // If we still have the original map, set in-object properties directly.
1782 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001783 // Both true and false are immovable immortal objects so no need for write
1784 // barrier.
1785 regexp->InObjectPropertyAtPut(
1786 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1787 regexp->InObjectPropertyAtPut(
1788 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1789 regexp->InObjectPropertyAtPut(
1790 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001791 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1792 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001793 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001794 return regexp;
1795 }
1796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 PropertyAttributes final =
1799 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1800 PropertyAttributes writable =
1801 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 source,
1806 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001809 global,
1810 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811 ASSERT(!result->IsFailure());
1812 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001814 ignoreCase,
1815 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001816 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 multiline,
1819 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
1821 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 Smi::FromInt(0),
1824 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827 return regexp;
1828}
1829
1830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001833 ASSERT(args.length() == 1);
1834 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1835 // This is necessary to enable fast checks for absence of elements
1836 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001838 return Smi::FromInt(0);
1839}
1840
1841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1843 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001845 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1847 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1848 Handle<JSFunction> optimized =
1849 isolate->factory()->NewFunction(key,
1850 JS_OBJECT_TYPE,
1851 JSObject::kHeaderSize,
1852 code,
1853 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001855 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 return optimized;
1857}
1858
1859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001860RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862 ASSERT(args.length() == 1);
1863 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1864
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001865 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1866 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1867 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1868 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1869 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1870 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1871 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001872
1873 return *holder;
1874}
1875
1876
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1878 NoHandleAllocation handle_free;
1879 ASSERT(args.length() == 1);
1880 CONVERT_CHECKED(JSFunction, function, args[0]);
1881 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001882 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 return isolate->heap()->undefined_value();
1884 }
1885 // Returns undefined for strict or native functions, or
1886 // the associated global receiver for "normal" functions.
1887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001888 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001889 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001890 return global_context->global()->global_receiver();
1891}
1892
1893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001894RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 ASSERT(args.length() == 4);
1897 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001898 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 Handle<String> pattern = args.at<String>(2);
1900 Handle<String> flags = args.at<String>(3);
1901
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001902 // Get the RegExp function from the context in the literals array.
1903 // This is the RegExp function from the context in which the
1904 // function was created. We do not use the RegExp function from the
1905 // current global context because this might be the RegExp function
1906 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001908 Handle<JSFunction>(
1909 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 // Compute the regular expression literal.
1911 bool has_pending_exception;
1912 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001913 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1914 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 return Failure::Exception();
1918 }
1919 literals->set(index, *regexp);
1920 return *regexp;
1921}
1922
1923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1);
1927
1928 CONVERT_CHECKED(JSFunction, f, args[0]);
1929 return f->shared()->name();
1930}
1931
1932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001933RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001934 NoHandleAllocation ha;
1935 ASSERT(args.length() == 2);
1936
1937 CONVERT_CHECKED(JSFunction, f, args[0]);
1938 CONVERT_CHECKED(String, name, args[1]);
1939 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001941}
1942
1943
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947 CONVERT_CHECKED(JSFunction, f, args[0]);
1948 return isolate->heap()->ToBoolean(
1949 f->shared()->name_should_print_as_anonymous());
1950}
1951
1952
1953RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1954 NoHandleAllocation ha;
1955 ASSERT(args.length() == 1);
1956 CONVERT_CHECKED(JSFunction, f, args[0]);
1957 f->shared()->set_name_should_print_as_anonymous(true);
1958 return isolate->heap()->undefined_value();
1959}
1960
1961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001962RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001963 NoHandleAllocation ha;
1964 ASSERT(args.length() == 1);
1965
1966 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001967 Object* obj = f->RemovePrototype();
1968 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001971}
1972
1973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 ASSERT(args.length() == 1);
1977
1978 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1980 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981
1982 return *GetScriptWrapper(Handle<Script>::cast(script));
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
1990 CONVERT_CHECKED(JSFunction, f, args[0]);
1991 return f->shared()->GetSourceCode();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
1999 CONVERT_CHECKED(JSFunction, fun, args[0]);
2000 int pos = fun->shared()->start_position();
2001 return Smi::FromInt(pos);
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002006 ASSERT(args.length() == 2);
2007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2010
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002011 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2012
2013 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002015}
2016
2017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002018RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 NoHandleAllocation ha;
2020 ASSERT(args.length() == 2);
2021
2022 CONVERT_CHECKED(JSFunction, fun, args[0]);
2023 CONVERT_CHECKED(String, name, args[1]);
2024 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 2);
2032
2033 CONVERT_CHECKED(JSFunction, fun, args[0]);
2034 CONVERT_CHECKED(Smi, length, args[1]);
2035 fun->shared()->set_length(length->value());
2036 return length;
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002142 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002148 // Set the code, scope info, formal parameter count,
2149 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002150 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002151 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002152 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002153 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002155 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002156 // Set the source code of the target function to undefined.
2157 // SetCode is only used for built-in constructors like String,
2158 // Array, and Object, and some web code
2159 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002160 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002161 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002162 // Clear the optimization hints related to the compiled code as these are no
2163 // longer valid when the code is overwritten.
2164 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 context = Handle<Context>(fun->context());
2166
2167 // Make sure we get a fresh copy of the literal vector to avoid
2168 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002169 int number_of_literals = fun->NumberOfLiterals();
2170 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002171 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173 // Insert the object, regexp and array functions in the literals
2174 // array prefix. These are the functions that will be used when
2175 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002176 literals->set(JSFunction::kLiteralGlobalContextIndex,
2177 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002180 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002181
2182 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2183 isolate->logger()->LogExistingFunction(
2184 shared, Handle<Code>(shared->code()));
2185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 }
2187
2188 target->set_context(*context);
2189 return *target;
2190}
2191
2192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002193RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195 ASSERT(args.length() == 2);
2196 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002197 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002198 RUNTIME_ASSERT(num >= 0);
2199 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002201}
2202
2203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2205 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002207 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002209 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002210 }
2211 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002213}
2214
2215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002216RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 NoHandleAllocation ha;
2218 ASSERT(args.length() == 2);
2219
2220 CONVERT_CHECKED(String, subject, args[0]);
2221 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002224 uint32_t i = 0;
2225 if (index->IsSmi()) {
2226 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228 i = value;
2229 } else {
2230 ASSERT(index->IsHeapNumber());
2231 double value = HeapNumber::cast(index)->value();
2232 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002233 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002234
2235 // Flatten the string. If someone wants to get a char at an index
2236 // in a cons string, it is likely that more indices will be
2237 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002238 Object* flat;
2239 { MaybeObject* maybe_flat = subject->TryFlatten();
2240 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2241 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002242 subject = String::cast(flat);
2243
2244 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 }
2247
2248 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002249}
2250
2251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002252RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 NoHandleAllocation ha;
2254 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256}
2257
lrn@chromium.org25156de2010-04-06 13:10:27 +00002258
2259class FixedArrayBuilder {
2260 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2262 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002263 length_(0),
2264 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 // Require a non-zero initial size. Ensures that doubling the size to
2266 // extend the array will work.
2267 ASSERT(initial_capacity > 0);
2268 }
2269
2270 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2271 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002272 length_(0),
2273 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002274 // Require a non-zero initial size. Ensures that doubling the size to
2275 // extend the array will work.
2276 ASSERT(backing_store->length() > 0);
2277 }
2278
2279 bool HasCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 return (length >= required_length);
2283 }
2284
2285 void EnsureCapacity(int elements) {
2286 int length = array_->length();
2287 int required_length = length_ + elements;
2288 if (length < required_length) {
2289 int new_length = length;
2290 do {
2291 new_length *= 2;
2292 } while (new_length < required_length);
2293 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002294 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 array_->CopyTo(0, *extended_array, 0, length_);
2296 array_ = extended_array;
2297 }
2298 }
2299
2300 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002301 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 ASSERT(length_ < capacity());
2303 array_->set(length_, value);
2304 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002305 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 }
2307
2308 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002309 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 ASSERT(length_ < capacity());
2311 array_->set(length_, value);
2312 length_++;
2313 }
2314
2315 Handle<FixedArray> array() {
2316 return array_;
2317 }
2318
2319 int length() {
2320 return length_;
2321 }
2322
2323 int capacity() {
2324 return array_->length();
2325 }
2326
2327 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 result_array->set_length(Smi::FromInt(length_));
2330 return result_array;
2331 }
2332
2333 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 target_array->set_length(Smi::FromInt(length_));
2336 return target_array;
2337 }
2338
2339 private:
2340 Handle<FixedArray> array_;
2341 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002342 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343};
2344
2345
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002346// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347const int kStringBuilderConcatHelperLengthBits = 11;
2348const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002349
2350template <typename schar>
2351static inline void StringBuilderConcatHelper(String*,
2352 schar*,
2353 FixedArray*,
2354 int);
2355
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2357 StringBuilderSubstringLength;
2358typedef BitField<int,
2359 kStringBuilderConcatHelperLengthBits,
2360 kStringBuilderConcatHelperPositionBits>
2361 StringBuilderSubstringPosition;
2362
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363
2364class ReplacementStringBuilder {
2365 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002366 ReplacementStringBuilder(Heap* heap,
2367 Handle<String> subject,
2368 int estimated_part_count)
2369 : heap_(heap),
2370 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002372 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002373 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 // Require a non-zero initial size. Ensures that doubling the size to
2375 // extend the array will work.
2376 ASSERT(estimated_part_count > 0);
2377 }
2378
lrn@chromium.org25156de2010-04-06 13:10:27 +00002379 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2380 int from,
2381 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 ASSERT(from >= 0);
2383 int length = to - from;
2384 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 if (StringBuilderSubstringLength::is_valid(length) &&
2386 StringBuilderSubstringPosition::is_valid(from)) {
2387 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2388 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002391 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 builder->Add(Smi::FromInt(-length));
2393 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002395 }
2396
2397
2398 void EnsureCapacity(int elements) {
2399 array_builder_.EnsureCapacity(elements);
2400 }
2401
2402
2403 void AddSubjectSlice(int from, int to) {
2404 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 }
2407
2408
2409 void AddString(Handle<String> string) {
2410 int length = string->length();
2411 ASSERT(length > 0);
2412 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002413 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002414 is_ascii_ = false;
2415 }
2416 IncrementCharacterCount(length);
2417 }
2418
2419
2420 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002421 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002422 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 }
2424
2425 Handle<String> joined_string;
2426 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002427 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 char* char_buffer = seq->GetChars();
2430 StringBuilderConcatHelper(*subject_,
2431 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 *array_builder_.array(),
2433 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002434 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 } else {
2436 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002437 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 uc16* char_buffer = seq->GetChars();
2440 StringBuilderConcatHelper(*subject_,
2441 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 *array_builder_.array(),
2443 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002444 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002445 }
2446 return joined_string;
2447 }
2448
2449
2450 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002451 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 V8::FatalProcessOutOfMemory("String.replace result too large.");
2453 }
2454 character_count_ += by;
2455 }
2456
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002458 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002460
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2463 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 }
2465
2466
ager@chromium.org04921a82011-06-27 13:21:41 +00002467 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2468 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 }
2470
2471
2472 void AddElement(Object* element) {
2473 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 ASSERT(array_builder_.capacity() > array_builder_.length());
2475 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 }
2477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002478 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002479 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 int character_count_;
2482 bool is_ascii_;
2483};
2484
2485
2486class CompiledReplacement {
2487 public:
2488 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002489 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490
2491 void Compile(Handle<String> replacement,
2492 int capture_count,
2493 int subject_length);
2494
2495 void Apply(ReplacementStringBuilder* builder,
2496 int match_from,
2497 int match_to,
2498 Handle<JSArray> last_match_info);
2499
2500 // Number of distinct parts of the replacement pattern.
2501 int parts() {
2502 return parts_.length();
2503 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002504
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002505 bool simple_hint() {
2506 return simple_hint_;
2507 }
2508
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509 private:
2510 enum PartType {
2511 SUBJECT_PREFIX = 1,
2512 SUBJECT_SUFFIX,
2513 SUBJECT_CAPTURE,
2514 REPLACEMENT_SUBSTRING,
2515 REPLACEMENT_STRING,
2516
2517 NUMBER_OF_PART_TYPES
2518 };
2519
2520 struct ReplacementPart {
2521 static inline ReplacementPart SubjectMatch() {
2522 return ReplacementPart(SUBJECT_CAPTURE, 0);
2523 }
2524 static inline ReplacementPart SubjectCapture(int capture_index) {
2525 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2526 }
2527 static inline ReplacementPart SubjectPrefix() {
2528 return ReplacementPart(SUBJECT_PREFIX, 0);
2529 }
2530 static inline ReplacementPart SubjectSuffix(int subject_length) {
2531 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2532 }
2533 static inline ReplacementPart ReplacementString() {
2534 return ReplacementPart(REPLACEMENT_STRING, 0);
2535 }
2536 static inline ReplacementPart ReplacementSubString(int from, int to) {
2537 ASSERT(from >= 0);
2538 ASSERT(to > from);
2539 return ReplacementPart(-from, to);
2540 }
2541
2542 // If tag <= 0 then it is the negation of a start index of a substring of
2543 // the replacement pattern, otherwise it's a value from PartType.
2544 ReplacementPart(int tag, int data)
2545 : tag(tag), data(data) {
2546 // Must be non-positive or a PartType value.
2547 ASSERT(tag < NUMBER_OF_PART_TYPES);
2548 }
2549 // Either a value of PartType or a non-positive number that is
2550 // the negation of an index into the replacement string.
2551 int tag;
2552 // The data value's interpretation depends on the value of tag:
2553 // tag == SUBJECT_PREFIX ||
2554 // tag == SUBJECT_SUFFIX: data is unused.
2555 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2556 // tag == REPLACEMENT_SUBSTRING ||
2557 // tag == REPLACEMENT_STRING: data is index into array of substrings
2558 // of the replacement string.
2559 // tag <= 0: Temporary representation of the substring of the replacement
2560 // string ranging over -tag .. data.
2561 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2562 // substring objects.
2563 int data;
2564 };
2565
2566 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002567 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 Vector<Char> characters,
2569 int capture_count,
2570 int subject_length) {
2571 int length = characters.length();
2572 int last = 0;
2573 for (int i = 0; i < length; i++) {
2574 Char c = characters[i];
2575 if (c == '$') {
2576 int next_index = i + 1;
2577 if (next_index == length) { // No next character!
2578 break;
2579 }
2580 Char c2 = characters[next_index];
2581 switch (c2) {
2582 case '$':
2583 if (i > last) {
2584 // There is a substring before. Include the first "$".
2585 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2586 last = next_index + 1; // Continue after the second "$".
2587 } else {
2588 // Let the next substring start with the second "$".
2589 last = next_index;
2590 }
2591 i = next_index;
2592 break;
2593 case '`':
2594 if (i > last) {
2595 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2596 }
2597 parts->Add(ReplacementPart::SubjectPrefix());
2598 i = next_index;
2599 last = i + 1;
2600 break;
2601 case '\'':
2602 if (i > last) {
2603 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2604 }
2605 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2606 i = next_index;
2607 last = i + 1;
2608 break;
2609 case '&':
2610 if (i > last) {
2611 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2612 }
2613 parts->Add(ReplacementPart::SubjectMatch());
2614 i = next_index;
2615 last = i + 1;
2616 break;
2617 case '0':
2618 case '1':
2619 case '2':
2620 case '3':
2621 case '4':
2622 case '5':
2623 case '6':
2624 case '7':
2625 case '8':
2626 case '9': {
2627 int capture_ref = c2 - '0';
2628 if (capture_ref > capture_count) {
2629 i = next_index;
2630 continue;
2631 }
2632 int second_digit_index = next_index + 1;
2633 if (second_digit_index < length) {
2634 // Peek ahead to see if we have two digits.
2635 Char c3 = characters[second_digit_index];
2636 if ('0' <= c3 && c3 <= '9') { // Double digits.
2637 int double_digit_ref = capture_ref * 10 + c3 - '0';
2638 if (double_digit_ref <= capture_count) {
2639 next_index = second_digit_index;
2640 capture_ref = double_digit_ref;
2641 }
2642 }
2643 }
2644 if (capture_ref > 0) {
2645 if (i > last) {
2646 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2647 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002648 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2650 last = next_index + 1;
2651 }
2652 i = next_index;
2653 break;
2654 }
2655 default:
2656 i = next_index;
2657 break;
2658 }
2659 }
2660 }
2661 if (length > last) {
2662 if (last == 0) {
2663 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002664 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 } else {
2666 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2667 }
2668 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002669 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 }
2671
2672 ZoneList<ReplacementPart> parts_;
2673 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002674 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002675};
2676
2677
2678void CompiledReplacement::Compile(Handle<String> replacement,
2679 int capture_count,
2680 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002681 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002683 String::FlatContent content = replacement->GetFlatContent();
2684 ASSERT(content.IsFlat());
2685 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToAsciiVector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 } else {
2691 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002692 simple_hint_ = ParseReplacementPattern(&parts_,
2693 content.ToUC16Vector(),
2694 capture_count,
2695 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002696 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002699 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700 int substring_index = 0;
2701 for (int i = 0, n = parts_.length(); i < n; i++) {
2702 int tag = parts_[i].tag;
2703 if (tag <= 0) { // A replacement string slice.
2704 int from = -tag;
2705 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 replacement_substrings_.Add(
2707 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 parts_[i].tag = REPLACEMENT_SUBSTRING;
2709 parts_[i].data = substring_index;
2710 substring_index++;
2711 } else if (tag == REPLACEMENT_STRING) {
2712 replacement_substrings_.Add(replacement);
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 }
2716 }
2717}
2718
2719
2720void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2721 int match_from,
2722 int match_to,
2723 Handle<JSArray> last_match_info) {
2724 for (int i = 0, n = parts_.length(); i < n; i++) {
2725 ReplacementPart part = parts_[i];
2726 switch (part.tag) {
2727 case SUBJECT_PREFIX:
2728 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2729 break;
2730 case SUBJECT_SUFFIX: {
2731 int subject_length = part.data;
2732 if (match_to < subject_length) {
2733 builder->AddSubjectSlice(match_to, subject_length);
2734 }
2735 break;
2736 }
2737 case SUBJECT_CAPTURE: {
2738 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002739 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002740 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2741 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2742 if (from >= 0 && to > from) {
2743 builder->AddSubjectSlice(from, to);
2744 }
2745 break;
2746 }
2747 case REPLACEMENT_SUBSTRING:
2748 case REPLACEMENT_STRING:
2749 builder->AddString(replacement_substrings_[part.data]);
2750 break;
2751 default:
2752 UNREACHABLE();
2753 }
2754 }
2755}
2756
2757
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002758void FindAsciiStringIndices(Vector<const char> subject,
2759 char pattern,
2760 ZoneList<int>* indices,
2761 unsigned int limit) {
2762 ASSERT(limit > 0);
2763 // Collect indices of pattern in subject using memchr.
2764 // Stop after finding at most limit values.
2765 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2766 const char* subject_end = subject_start + subject.length();
2767 const char* pos = subject_start;
2768 while (limit > 0) {
2769 pos = reinterpret_cast<const char*>(
2770 memchr(pos, pattern, subject_end - pos));
2771 if (pos == NULL) return;
2772 indices->Add(static_cast<int>(pos - subject_start));
2773 pos++;
2774 limit--;
2775 }
2776}
2777
2778
2779template <typename SubjectChar, typename PatternChar>
2780void FindStringIndices(Isolate* isolate,
2781 Vector<const SubjectChar> subject,
2782 Vector<const PatternChar> pattern,
2783 ZoneList<int>* indices,
2784 unsigned int limit) {
2785 ASSERT(limit > 0);
2786 // Collect indices of pattern in subject.
2787 // Stop after finding at most limit values.
2788 int pattern_length = pattern.length();
2789 int index = 0;
2790 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2791 while (limit > 0) {
2792 index = search.Search(subject, index);
2793 if (index < 0) return;
2794 indices->Add(index);
2795 index += pattern_length;
2796 limit--;
2797 }
2798}
2799
2800
2801void FindStringIndicesDispatch(Isolate* isolate,
2802 String* subject,
2803 String* pattern,
2804 ZoneList<int>* indices,
2805 unsigned int limit) {
2806 {
2807 AssertNoAllocation no_gc;
2808 String::FlatContent subject_content = subject->GetFlatContent();
2809 String::FlatContent pattern_content = pattern->GetFlatContent();
2810 ASSERT(subject_content.IsFlat());
2811 ASSERT(pattern_content.IsFlat());
2812 if (subject_content.IsAscii()) {
2813 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2814 if (pattern_content.IsAscii()) {
2815 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2816 if (pattern_vector.length() == 1) {
2817 FindAsciiStringIndices(subject_vector,
2818 pattern_vector[0],
2819 indices,
2820 limit);
2821 } else {
2822 FindStringIndices(isolate,
2823 subject_vector,
2824 pattern_vector,
2825 indices,
2826 limit);
2827 }
2828 } else {
2829 FindStringIndices(isolate,
2830 subject_vector,
2831 pattern_content.ToUC16Vector(),
2832 indices,
2833 limit);
2834 }
2835 } else {
2836 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002837 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToAsciiVector(),
2841 indices,
2842 limit);
2843 } else {
2844 FindStringIndices(isolate,
2845 subject_vector,
2846 pattern_content.ToUC16Vector(),
2847 indices,
2848 limit);
2849 }
2850 }
2851 }
2852}
2853
2854
2855template<typename ResultSeqString>
2856MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2857 Isolate* isolate,
2858 Handle<String> subject,
2859 Handle<JSRegExp> pattern_regexp,
2860 Handle<String> replacement) {
2861 ASSERT(subject->IsFlat());
2862 ASSERT(replacement->IsFlat());
2863
2864 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2865 ZoneList<int> indices(8);
2866 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2867 String* pattern =
2868 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2869 int subject_len = subject->length();
2870 int pattern_len = pattern->length();
2871 int replacement_len = replacement->length();
2872
2873 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2874
2875 int matches = indices.length();
2876 if (matches == 0) return *subject;
2877
2878 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2879 int subject_pos = 0;
2880 int result_pos = 0;
2881
2882 Handle<ResultSeqString> result;
2883 if (ResultSeqString::kHasAsciiEncoding) {
2884 result = Handle<ResultSeqString>::cast(
2885 isolate->factory()->NewRawAsciiString(result_len));
2886 } else {
2887 result = Handle<ResultSeqString>::cast(
2888 isolate->factory()->NewRawTwoByteString(result_len));
2889 }
2890
2891 for (int i = 0; i < matches; i++) {
2892 // Copy non-matched subject content.
2893 if (subject_pos < indices.at(i)) {
2894 String::WriteToFlat(*subject,
2895 result->GetChars() + result_pos,
2896 subject_pos,
2897 indices.at(i));
2898 result_pos += indices.at(i) - subject_pos;
2899 }
2900
2901 // Replace match.
2902 if (replacement_len > 0) {
2903 String::WriteToFlat(*replacement,
2904 result->GetChars() + result_pos,
2905 0,
2906 replacement_len);
2907 result_pos += replacement_len;
2908 }
2909
2910 subject_pos = indices.at(i) + pattern_len;
2911 }
2912 // Add remaining subject content at the end.
2913 if (subject_pos < subject_len) {
2914 String::WriteToFlat(*subject,
2915 result->GetChars() + result_pos,
2916 subject_pos,
2917 subject_len);
2918 }
2919 return *result;
2920}
2921
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002922
lrn@chromium.org303ada72010-10-27 09:33:13 +00002923MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002924 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002925 String* subject,
2926 JSRegExp* regexp,
2927 String* replacement,
2928 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002929 ASSERT(subject->IsFlat());
2930 ASSERT(replacement->IsFlat());
2931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002932 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933
2934 int length = subject->length();
2935 Handle<String> subject_handle(subject);
2936 Handle<JSRegExp> regexp_handle(regexp);
2937 Handle<String> replacement_handle(replacement);
2938 Handle<JSArray> last_match_info_handle(last_match_info);
2939 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2940 subject_handle,
2941 0,
2942 last_match_info_handle);
2943 if (match.is_null()) {
2944 return Failure::Exception();
2945 }
2946 if (match->IsNull()) {
2947 return *subject_handle;
2948 }
2949
2950 int capture_count = regexp_handle->CaptureCount();
2951
2952 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002953 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 CompiledReplacement compiled_replacement;
2955 compiled_replacement.Compile(replacement_handle,
2956 capture_count,
2957 length);
2958
2959 bool is_global = regexp_handle->GetFlags().is_global();
2960
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002961 // Shortcut for simple non-regexp global replacements
2962 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002963 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002964 compiled_replacement.simple_hint()) {
2965 if (subject_handle->HasOnlyAsciiChars() &&
2966 replacement_handle->HasOnlyAsciiChars()) {
2967 return StringReplaceStringWithString<SeqAsciiString>(
2968 isolate, subject_handle, regexp_handle, replacement_handle);
2969 } else {
2970 return StringReplaceStringWithString<SeqTwoByteString>(
2971 isolate, subject_handle, regexp_handle, replacement_handle);
2972 }
2973 }
2974
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002975 // Guessing the number of parts that the final result string is built
2976 // from. Global regexps can match any number of times, so we guess
2977 // conservatively.
2978 int expected_parts =
2979 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 ReplacementStringBuilder builder(isolate->heap(),
2981 subject_handle,
2982 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983
2984 // Index of end of last match.
2985 int prev = 0;
2986
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002987 // Number of parts added by compiled replacement plus preceeding
2988 // string and possibly suffix after last match. It is possible for
2989 // all components to use two elements when encoded as two smis.
2990 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002991 bool matched = true;
2992 do {
2993 ASSERT(last_match_info_handle->HasFastElements());
2994 // Increase the capacity of the builder before entering local handle-scope,
2995 // so its internal buffer can safely allocate a new handle if it grows.
2996 builder.EnsureCapacity(parts_added_per_loop);
2997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 int start, end;
3000 {
3001 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003002 FixedArray* match_info_array =
3003 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 ASSERT_EQ(capture_count * 2 + 2,
3006 RegExpImpl::GetLastCaptureCount(match_info_array));
3007 start = RegExpImpl::GetCapture(match_info_array, 0);
3008 end = RegExpImpl::GetCapture(match_info_array, 1);
3009 }
3010
3011 if (prev < start) {
3012 builder.AddSubjectSlice(prev, start);
3013 }
3014 compiled_replacement.Apply(&builder,
3015 start,
3016 end,
3017 last_match_info_handle);
3018 prev = end;
3019
3020 // Only continue checking for global regexps.
3021 if (!is_global) break;
3022
3023 // Continue from where the match ended, unless it was an empty match.
3024 int next = end;
3025 if (start == end) {
3026 next = end + 1;
3027 if (next > length) break;
3028 }
3029
3030 match = RegExpImpl::Exec(regexp_handle,
3031 subject_handle,
3032 next,
3033 last_match_info_handle);
3034 if (match.is_null()) {
3035 return Failure::Exception();
3036 }
3037 matched = !match->IsNull();
3038 } while (matched);
3039
3040 if (prev < length) {
3041 builder.AddSubjectSlice(prev, length);
3042 }
3043
3044 return *(builder.ToString());
3045}
3046
3047
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003049MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003051 String* subject,
3052 JSRegExp* regexp,
3053 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003054 ASSERT(subject->IsFlat());
3055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003056 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003057
3058 Handle<String> subject_handle(subject);
3059 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003060
3061 // Shortcut for simple non-regexp global replacements
3062 if (regexp_handle->GetFlags().is_global() &&
3063 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3064 Handle<String> empty_string_handle(HEAP->empty_string());
3065 if (subject_handle->HasOnlyAsciiChars()) {
3066 return StringReplaceStringWithString<SeqAsciiString>(
3067 isolate, subject_handle, regexp_handle, empty_string_handle);
3068 } else {
3069 return StringReplaceStringWithString<SeqTwoByteString>(
3070 isolate, subject_handle, regexp_handle, empty_string_handle);
3071 }
3072 }
3073
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003074 Handle<JSArray> last_match_info_handle(last_match_info);
3075 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3076 subject_handle,
3077 0,
3078 last_match_info_handle);
3079 if (match.is_null()) return Failure::Exception();
3080 if (match->IsNull()) return *subject_handle;
3081
3082 ASSERT(last_match_info_handle->HasFastElements());
3083
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003084 int start, end;
3085 {
3086 AssertNoAllocation match_info_array_is_not_in_a_handle;
3087 FixedArray* match_info_array =
3088 FixedArray::cast(last_match_info_handle->elements());
3089
3090 start = RegExpImpl::GetCapture(match_info_array, 0);
3091 end = RegExpImpl::GetCapture(match_info_array, 1);
3092 }
3093
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003094 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 int new_length = length - (end - start);
3096 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 }
3099 Handle<ResultSeqString> answer;
3100 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 answer = Handle<ResultSeqString>::cast(
3102 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 answer = Handle<ResultSeqString>::cast(
3105 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003106 }
3107
3108 // If the regexp isn't global, only match once.
3109 if (!regexp_handle->GetFlags().is_global()) {
3110 if (start > 0) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars(),
3113 0,
3114 start);
3115 }
3116 if (end < length) {
3117 String::WriteToFlat(*subject_handle,
3118 answer->GetChars() + start,
3119 end,
3120 length);
3121 }
3122 return *answer;
3123 }
3124
3125 int prev = 0; // Index of end of last match.
3126 int next = 0; // Start of next search (prev unless last match was empty).
3127 int position = 0;
3128
3129 do {
3130 if (prev < start) {
3131 // Add substring subject[prev;start] to answer string.
3132 String::WriteToFlat(*subject_handle,
3133 answer->GetChars() + position,
3134 prev,
3135 start);
3136 position += start - prev;
3137 }
3138 prev = end;
3139 next = end;
3140 // Continue from where the match ended, unless it was an empty match.
3141 if (start == end) {
3142 next++;
3143 if (next > length) break;
3144 }
3145 match = RegExpImpl::Exec(regexp_handle,
3146 subject_handle,
3147 next,
3148 last_match_info_handle);
3149 if (match.is_null()) return Failure::Exception();
3150 if (match->IsNull()) break;
3151
3152 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003153 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003154 {
3155 AssertNoAllocation match_info_array_is_not_in_a_handle;
3156 FixedArray* match_info_array =
3157 FixedArray::cast(last_match_info_handle->elements());
3158 start = RegExpImpl::GetCapture(match_info_array, 0);
3159 end = RegExpImpl::GetCapture(match_info_array, 1);
3160 }
3161 } while (true);
3162
3163 if (prev < length) {
3164 // Add substring subject[prev;length] to answer string.
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars() + position,
3167 prev,
3168 length);
3169 position += length - prev;
3170 }
3171
3172 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003174 }
3175
3176 // Shorten string and fill
3177 int string_size = ResultSeqString::SizeFor(position);
3178 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3179 int delta = allocated_string_size - string_size;
3180
3181 answer->set_length(position);
3182 if (delta == 0) return *answer;
3183
3184 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003185 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003186 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3187 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3188 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003189
3190 return *answer;
3191}
3192
3193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003195 ASSERT(args.length() == 4);
3196
3197 CONVERT_CHECKED(String, subject, args[0]);
3198 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003199 Object* flat_subject;
3200 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3201 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3202 return maybe_flat_subject;
3203 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003204 }
3205 subject = String::cast(flat_subject);
3206 }
3207
3208 CONVERT_CHECKED(String, replacement, args[2]);
3209 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003210 Object* flat_replacement;
3211 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3212 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3213 return maybe_flat_replacement;
3214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 }
3216 replacement = String::cast(flat_replacement);
3217 }
3218
3219 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3220 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3221
3222 ASSERT(last_match_info->HasFastElements());
3223
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003224 if (replacement->length() == 0) {
3225 if (subject->HasOnlyAsciiChars()) {
3226 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 } else {
3229 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003230 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003231 }
3232 }
3233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 return StringReplaceRegExpWithString(isolate,
3235 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003236 regexp,
3237 replacement,
3238 last_match_info);
3239}
3240
3241
ager@chromium.org7c537e22008-10-16 08:43:32 +00003242// Perform string match of pattern on subject, starting at start index.
3243// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003244// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245int Runtime::StringMatch(Isolate* isolate,
3246 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003247 Handle<String> pat,
3248 int start_index) {
3249 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003250 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003251
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003252 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003253 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003254
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003256 if (start_index + pattern_length > subject_length) return -1;
3257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003258 if (!sub->IsFlat()) FlattenString(sub);
3259 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003260
ager@chromium.org7c537e22008-10-16 08:43:32 +00003261 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003262 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003263 String::FlatContent seq_sub = sub->GetFlatContent();
3264 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003265
ager@chromium.org7c537e22008-10-16 08:43:32 +00003266 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003267 if (seq_pat.IsAscii()) {
3268 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3269 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003271 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 pat_vector,
3273 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003275 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003276 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 pat_vector,
3278 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003279 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003280 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3281 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003282 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003283 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 pat_vector,
3285 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003288 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 pat_vector,
3290 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003291}
3292
3293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003296 ASSERT(args.length() == 3);
3297
ager@chromium.org7c537e22008-10-16 08:43:32 +00003298 CONVERT_ARG_CHECKED(String, sub, 0);
3299 CONVERT_ARG_CHECKED(String, pat, 1);
3300
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003301 Object* index = args[2];
3302 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003303 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003304
ager@chromium.org870a0b62008-11-04 11:43:05 +00003305 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 int position =
3307 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003308 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309}
3310
3311
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003312template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003313static int StringMatchBackwards(Vector<const schar> subject,
3314 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003315 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003316 int pattern_length = pattern.length();
3317 ASSERT(pattern_length >= 1);
3318 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003319
3320 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003321 for (int i = 0; i < pattern_length; i++) {
3322 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003323 if (c > String::kMaxAsciiCharCode) {
3324 return -1;
3325 }
3326 }
3327 }
3328
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003329 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003331 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003332 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003333 while (j < pattern_length) {
3334 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003335 break;
3336 }
3337 j++;
3338 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003339 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003340 return i;
3341 }
3342 }
3343 return -1;
3344}
3345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003346RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 ASSERT(args.length() == 3);
3349
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003350 CONVERT_ARG_CHECKED(String, sub, 0);
3351 CONVERT_ARG_CHECKED(String, pat, 1);
3352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003355 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003357 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003358 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003360 if (start_index + pat_length > sub_length) {
3361 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364 if (pat_length == 0) {
3365 return Smi::FromInt(start_index);
3366 }
3367
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003368 if (!sub->IsFlat()) FlattenString(sub);
3369 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003370
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003372 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3373
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 String::FlatContent sub_content = sub->GetFlatContent();
3375 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003376
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003377 if (pat_content.IsAscii()) {
3378 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3379 if (sub_content.IsAscii()) {
3380 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003381 pat_vector,
3382 start_index);
3383 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003384 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003385 pat_vector,
3386 start_index);
3387 }
3388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3390 if (sub_content.IsAscii()) {
3391 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 pat_vector,
3393 start_index);
3394 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396 pat_vector,
3397 start_index);
3398 }
3399 }
3400
3401 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 NoHandleAllocation ha;
3407 ASSERT(args.length() == 2);
3408
3409 CONVERT_CHECKED(String, str1, args[0]);
3410 CONVERT_CHECKED(String, str2, args[1]);
3411
3412 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003413 int str1_length = str1->length();
3414 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415
3416 // Decide trivial cases without flattening.
3417 if (str1_length == 0) {
3418 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3419 return Smi::FromInt(-str2_length);
3420 } else {
3421 if (str2_length == 0) return Smi::FromInt(str1_length);
3422 }
3423
3424 int end = str1_length < str2_length ? str1_length : str2_length;
3425
3426 // No need to flatten if we are going to find the answer on the first
3427 // character. At this point we know there is at least one character
3428 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003429 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 if (d != 0) return Smi::FromInt(d);
3431
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003432 str1->TryFlatten();
3433 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003435 StringInputBuffer& buf1 =
3436 *isolate->runtime_state()->string_locale_compare_buf1();
3437 StringInputBuffer& buf2 =
3438 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439
3440 buf1.Reset(str1);
3441 buf2.Reset(str2);
3442
3443 for (int i = 0; i < end; i++) {
3444 uint16_t char1 = buf1.GetNext();
3445 uint16_t char2 = buf2.GetNext();
3446 if (char1 != char2) return Smi::FromInt(char1 - char2);
3447 }
3448
3449 return Smi::FromInt(str1_length - str2_length);
3450}
3451
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 NoHandleAllocation ha;
3455 ASSERT(args.length() == 3);
3456
3457 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003458 int start, end;
3459 // We have a fast integer-only case here to avoid a conversion to double in
3460 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003461 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3462 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3463 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3464 start = from_number;
3465 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003466 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003467 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3468 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003469 start = FastD2I(from_number);
3470 end = FastD2I(to_number);
3471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 RUNTIME_ASSERT(end >= start);
3473 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003474 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003475 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003476 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477}
3478
3479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003481 ASSERT_EQ(3, args.length());
3482
3483 CONVERT_ARG_CHECKED(String, subject, 0);
3484 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3485 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3486 HandleScope handles;
3487
3488 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3489
3490 if (match.is_null()) {
3491 return Failure::Exception();
3492 }
3493 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003495 }
3496 int length = subject->length();
3497
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003498 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003499 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003500 int start;
3501 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003502 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003503 {
3504 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003505 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003506 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3507 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3508 }
3509 offsets.Add(start);
3510 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003511 if (start == end) if (++end > length) break;
3512 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 if (match.is_null()) {
3514 return Failure::Exception();
3515 }
3516 } while (!match->IsNull());
3517 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003518 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003519 Handle<String> substring = isolate->factory()->
3520 NewSubString(subject, offsets.at(0), offsets.at(1));
3521 elements->set(0, *substring);
3522 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003523 int from = offsets.at(i * 2);
3524 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003525 Handle<String> substring = isolate->factory()->
3526 NewProperSubString(subject, from, to);
3527 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003530 result->set_length(Smi::FromInt(matches));
3531 return *result;
3532}
3533
3534
lrn@chromium.org25156de2010-04-06 13:10:27 +00003535// Two smis before and after the match, for very long strings.
3536const int kMaxBuilderEntriesPerRegExpMatch = 5;
3537
3538
3539static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3540 Handle<JSArray> last_match_info,
3541 int match_start,
3542 int match_end) {
3543 // Fill last_match_info with a single capture.
3544 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3545 AssertNoAllocation no_gc;
3546 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3547 RegExpImpl::SetLastCaptureCount(elements, 2);
3548 RegExpImpl::SetLastInput(elements, *subject);
3549 RegExpImpl::SetLastSubject(elements, *subject);
3550 RegExpImpl::SetCapture(elements, 0, match_start);
3551 RegExpImpl::SetCapture(elements, 1, match_end);
3552}
3553
3554
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003555template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556static bool SearchStringMultiple(Isolate* isolate,
3557 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003558 Vector<const PatternChar> pattern,
3559 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003560 FixedArrayBuilder* builder,
3561 int* match_pos) {
3562 int pos = *match_pos;
3563 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003564 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003567 while (pos <= max_search_start) {
3568 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3569 *match_pos = pos;
3570 return false;
3571 }
3572 // Position of end of previous match.
3573 int match_end = pos + pattern_length;
3574 int new_pos = search.Search(subject, match_end);
3575 if (new_pos >= 0) {
3576 // A match.
3577 if (new_pos > match_end) {
3578 ReplacementStringBuilder::AddSubjectSlice(builder,
3579 match_end,
3580 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003581 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582 pos = new_pos;
3583 builder->Add(pattern_string);
3584 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003585 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003586 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003587 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589 if (pos < max_search_start) {
3590 ReplacementStringBuilder::AddSubjectSlice(builder,
3591 pos + pattern_length,
3592 subject_length);
3593 }
3594 *match_pos = pos;
3595 return true;
3596}
3597
3598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599static bool SearchStringMultiple(Isolate* isolate,
3600 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003601 Handle<String> pattern,
3602 Handle<JSArray> last_match_info,
3603 FixedArrayBuilder* builder) {
3604 ASSERT(subject->IsFlat());
3605 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003606
3607 // Treating as if a previous match was before first character.
3608 int match_pos = -pattern->length();
3609
3610 for (;;) { // Break when search complete.
3611 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3612 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003613 String::FlatContent subject_content = subject->GetFlatContent();
3614 String::FlatContent pattern_content = pattern->GetFlatContent();
3615 if (subject_content.IsAscii()) {
3616 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3617 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 if (SearchStringMultiple(isolate,
3619 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003620 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003622 builder,
3623 &match_pos)) break;
3624 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 if (SearchStringMultiple(isolate,
3626 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003628 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003629 builder,
3630 &match_pos)) break;
3631 }
3632 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003633 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3634 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 if (SearchStringMultiple(isolate,
3636 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003637 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003638 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 builder,
3640 &match_pos)) break;
3641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 if (SearchStringMultiple(isolate,
3643 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003644 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003645 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003646 builder,
3647 &match_pos)) break;
3648 }
3649 }
3650 }
3651
3652 if (match_pos >= 0) {
3653 SetLastMatchInfoNoCaptures(subject,
3654 last_match_info,
3655 match_pos,
3656 match_pos + pattern->length());
3657 return true;
3658 }
3659 return false; // No matches at all.
3660}
3661
3662
3663static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003665 Handle<String> subject,
3666 Handle<JSRegExp> regexp,
3667 Handle<JSArray> last_match_array,
3668 FixedArrayBuilder* builder) {
3669 ASSERT(subject->IsFlat());
3670 int match_start = -1;
3671 int match_end = 0;
3672 int pos = 0;
3673 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3674 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3675
3676 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003677 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003679 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003680
3681 for (;;) { // Break on failure, return on exception.
3682 RegExpImpl::IrregexpResult result =
3683 RegExpImpl::IrregexpExecOnce(regexp,
3684 subject,
3685 pos,
3686 register_vector);
3687 if (result == RegExpImpl::RE_SUCCESS) {
3688 match_start = register_vector[0];
3689 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3690 if (match_end < match_start) {
3691 ReplacementStringBuilder::AddSubjectSlice(builder,
3692 match_end,
3693 match_start);
3694 }
3695 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 if (!first) {
3698 builder->Add(*isolate->factory()->NewProperSubString(subject,
3699 match_start,
3700 match_end));
3701 } else {
3702 builder->Add(*isolate->factory()->NewSubString(subject,
3703 match_start,
3704 match_end));
3705 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 if (match_start != match_end) {
3707 pos = match_end;
3708 } else {
3709 pos = match_end + 1;
3710 if (pos > subject_length) break;
3711 }
3712 } else if (result == RegExpImpl::RE_FAILURE) {
3713 break;
3714 } else {
3715 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3716 return result;
3717 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003718 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 }
3720
3721 if (match_start >= 0) {
3722 if (match_end < subject_length) {
3723 ReplacementStringBuilder::AddSubjectSlice(builder,
3724 match_end,
3725 subject_length);
3726 }
3727 SetLastMatchInfoNoCaptures(subject,
3728 last_match_array,
3729 match_start,
3730 match_end);
3731 return RegExpImpl::RE_SUCCESS;
3732 } else {
3733 return RegExpImpl::RE_FAILURE; // No matches at all.
3734 }
3735}
3736
3737
3738static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003740 Handle<String> subject,
3741 Handle<JSRegExp> regexp,
3742 Handle<JSArray> last_match_array,
3743 FixedArrayBuilder* builder) {
3744
3745 ASSERT(subject->IsFlat());
3746 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3747 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3748
3749 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003750 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003751
3752 RegExpImpl::IrregexpResult result =
3753 RegExpImpl::IrregexpExecOnce(regexp,
3754 subject,
3755 0,
3756 register_vector);
3757
3758 int capture_count = regexp->CaptureCount();
3759 int subject_length = subject->length();
3760
3761 // Position to search from.
3762 int pos = 0;
3763 // End of previous match. Differs from pos if match was empty.
3764 int match_end = 0;
3765 if (result == RegExpImpl::RE_SUCCESS) {
3766 // Need to keep a copy of the previous match for creating last_match_info
3767 // at the end, so we have two vectors that we swap between.
3768 OffsetsVector registers2(required_registers);
3769 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003770 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003771 do {
3772 int match_start = register_vector[0];
3773 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3774 if (match_end < match_start) {
3775 ReplacementStringBuilder::AddSubjectSlice(builder,
3776 match_end,
3777 match_start);
3778 }
3779 match_end = register_vector[1];
3780
3781 {
3782 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003783 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003784 // Arguments array to replace function is match, captures, index and
3785 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 Handle<FixedArray> elements =
3787 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 Handle<String> match;
3789 if (!first) {
3790 match = isolate->factory()->NewProperSubString(subject,
3791 match_start,
3792 match_end);
3793 } else {
3794 match = isolate->factory()->NewSubString(subject,
3795 match_start,
3796 match_end);
3797 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003798 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003799 for (int i = 1; i <= capture_count; i++) {
3800 int start = register_vector[i * 2];
3801 if (start >= 0) {
3802 int end = register_vector[i * 2 + 1];
3803 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 Handle<String> substring;
3805 if (!first) {
3806 substring = isolate->factory()->NewProperSubString(subject,
3807 start,
3808 end);
3809 } else {
3810 substring = isolate->factory()->NewSubString(subject, start, end);
3811 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003812 elements->set(i, *substring);
3813 } else {
3814 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003815 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 }
3817 }
3818 elements->set(capture_count + 1, Smi::FromInt(match_start));
3819 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003821 }
3822 // Swap register vectors, so the last successful match is in
3823 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003824 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 prev_register_vector = register_vector;
3826 register_vector = tmp;
3827
3828 if (match_end > match_start) {
3829 pos = match_end;
3830 } else {
3831 pos = match_end + 1;
3832 if (pos > subject_length) {
3833 break;
3834 }
3835 }
3836
3837 result = RegExpImpl::IrregexpExecOnce(regexp,
3838 subject,
3839 pos,
3840 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003841 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003842 } while (result == RegExpImpl::RE_SUCCESS);
3843
3844 if (result != RegExpImpl::RE_EXCEPTION) {
3845 // Finished matching, with at least one match.
3846 if (match_end < subject_length) {
3847 ReplacementStringBuilder::AddSubjectSlice(builder,
3848 match_end,
3849 subject_length);
3850 }
3851
3852 int last_match_capture_count = (capture_count + 1) * 2;
3853 int last_match_array_size =
3854 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3855 last_match_array->EnsureSize(last_match_array_size);
3856 AssertNoAllocation no_gc;
3857 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3858 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3859 RegExpImpl::SetLastSubject(elements, *subject);
3860 RegExpImpl::SetLastInput(elements, *subject);
3861 for (int i = 0; i < last_match_capture_count; i++) {
3862 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3863 }
3864 return RegExpImpl::RE_SUCCESS;
3865 }
3866 }
3867 // No matches at all, return failure or exception result directly.
3868 return result;
3869}
3870
3871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003872RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003873 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875
3876 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003877 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3879 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3880 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3881
3882 ASSERT(last_match_info->HasFastElements());
3883 ASSERT(regexp->GetFlags().is_global());
3884 Handle<FixedArray> result_elements;
3885 if (result_array->HasFastElements()) {
3886 result_elements =
3887 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003888 }
3889 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 }
3892 FixedArrayBuilder builder(result_elements);
3893
3894 if (regexp->TypeTag() == JSRegExp::ATOM) {
3895 Handle<String> pattern(
3896 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 if (SearchStringMultiple(isolate, subject, pattern,
3899 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003900 return *builder.ToJSArray(result_array);
3901 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003902 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003903 }
3904
3905 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3906
3907 RegExpImpl::IrregexpResult result;
3908 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 result = SearchRegExpNoCaptureMultiple(isolate,
3910 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 regexp,
3912 last_match_info,
3913 &builder);
3914 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003915 result = SearchRegExpMultiple(isolate,
3916 subject,
3917 regexp,
3918 last_match_info,
3919 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003920 }
3921 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3924 return Failure::Exception();
3925}
3926
3927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929 NoHandleAllocation ha;
3930 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003931 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003932 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003934 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003935 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003936 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003938 // Character array used for conversion.
3939 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 return isolate->heap()->
3941 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003942 }
3943 }
3944
3945 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003946 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
3950 if (isinf(value)) {
3951 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003952 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003954 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 MaybeObject* result =
3958 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 DeleteArray(str);
3960 return result;
3961}
3962
3963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003964RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 NoHandleAllocation ha;
3966 ASSERT(args.length() == 2);
3967
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003968 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
3972 if (isinf(value)) {
3973 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003974 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003976 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 int f = FastD2I(f_number);
3980 RUNTIME_ASSERT(f >= 0);
3981 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 MaybeObject* res =
3983 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986}
3987
3988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 NoHandleAllocation ha;
3991 ASSERT(args.length() == 2);
3992
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003993 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003995 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 }
3997 if (isinf(value)) {
3998 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003999 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004001 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004003 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 int f = FastD2I(f_number);
4005 RUNTIME_ASSERT(f >= -1 && f <= 20);
4006 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 MaybeObject* res =
4008 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011}
4012
4013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 NoHandleAllocation ha;
4016 ASSERT(args.length() == 2);
4017
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004018 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
4022 if (isinf(value)) {
4023 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004026 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004028 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 int f = FastD2I(f_number);
4030 RUNTIME_ASSERT(f >= 1 && f <= 21);
4031 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 MaybeObject* res =
4033 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036}
4037
4038
4039// Returns a single character string where first character equals
4040// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004042 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004043 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004044 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004045 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004047 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048}
4049
4050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4052 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 // Handle [] indexing on Strings
4055 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4057 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 }
4059
4060 // Handle [] indexing on String objects
4061 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004062 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4063 Handle<Object> result =
4064 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4065 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
4067
4068 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004069 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 return prototype->GetElement(index);
4071 }
4072
4073 return object->GetElement(index);
4074}
4075
4076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4078 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004083 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004085 isolate->factory()->NewTypeError("non_object_property_load",
4086 HandleVector(args, 2));
4087 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 }
4089
4090 // Check if the given key is an array index.
4091 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004092 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095
4096 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004099 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 bool has_pending_exception = false;
4102 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004105 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 }
4107
ager@chromium.org32912102009-01-16 10:38:43 +00004108 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 // the element if so.
4110 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004111 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004113 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 }
4115}
4116
4117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004118RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 NoHandleAllocation ha;
4120 ASSERT(args.length() == 2);
4121
4122 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126}
4127
4128
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004129MaybeObject* TransitionElements(Handle<Object> object,
4130 ElementsKind to_kind,
4131 Isolate* isolate) {
4132 HandleScope scope(isolate);
4133 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4134 ElementsKind from_kind =
4135 Handle<JSObject>::cast(object)->map()->elements_kind();
4136 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4137 Handle<Object> result =
4138 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4139 if (result.is_null()) return isolate->ThrowIllegalOperation();
4140 return *result;
4141 }
4142 return isolate->ThrowIllegalOperation();
4143}
4144
4145
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004146// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004147RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004148 NoHandleAllocation ha;
4149 ASSERT(args.length() == 2);
4150
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004151 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004152 // itself.
4153 //
4154 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004155 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004156 // global proxy object never has properties. This is the case
4157 // because the global proxy object forwards everything to its hidden
4158 // prototype including local lookups.
4159 //
4160 // Additionally, we need to make sure that we do not cache results
4161 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004162 if (args[0]->IsJSObject()) {
4163 if (!args[0]->IsJSGlobalProxy() &&
4164 !args[0]->IsAccessCheckNeeded() &&
4165 args[1]->IsString()) {
4166 JSObject* receiver = JSObject::cast(args[0]);
4167 String* key = String::cast(args[1]);
4168 if (receiver->HasFastProperties()) {
4169 // Attempt to use lookup cache.
4170 Map* receiver_map = receiver->map();
4171 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4172 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4173 if (offset != -1) {
4174 Object* value = receiver->FastPropertyAt(offset);
4175 return value->IsTheHole()
4176 ? isolate->heap()->undefined_value()
4177 : value;
4178 }
4179 // Lookup cache miss. Perform lookup and update the cache if
4180 // appropriate.
4181 LookupResult result(isolate);
4182 receiver->LocalLookup(key, &result);
4183 if (result.IsProperty() && result.type() == FIELD) {
4184 int offset = result.GetFieldIndex();
4185 keyed_lookup_cache->Update(receiver_map, key, offset);
4186 return receiver->FastPropertyAt(offset);
4187 }
4188 } else {
4189 // Attempt dictionary lookup.
4190 StringDictionary* dictionary = receiver->property_dictionary();
4191 int entry = dictionary->FindEntry(key);
4192 if ((entry != StringDictionary::kNotFound) &&
4193 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4194 Object* value = dictionary->ValueAt(entry);
4195 if (!receiver->IsGlobalObject()) return value;
4196 value = JSGlobalPropertyCell::cast(value)->value();
4197 if (!value->IsTheHole()) return value;
4198 // If value is the hole do the general lookup.
4199 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004201 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4202 // JSObject without a string key. If the key is a Smi, check for a
4203 // definite out-of-bounds access to elements, which is a strong indicator
4204 // that subsequent accesses will also call the runtime. Proactively
4205 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4206 // doubles for those future calls in the case that the elements would
4207 // become FAST_DOUBLE_ELEMENTS.
4208 Handle<JSObject> js_object(args.at<JSObject>(0));
4209 ElementsKind elements_kind = js_object->GetElementsKind();
4210 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4211 elements_kind == FAST_DOUBLE_ELEMENTS) {
4212 FixedArrayBase* elements = js_object->elements();
4213 if (args.at<Smi>(1)->value() >= elements->length()) {
4214 MaybeObject* maybe_object = TransitionElements(js_object,
4215 FAST_ELEMENTS,
4216 isolate);
4217 if (maybe_object->IsFailure()) return maybe_object;
4218 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004219 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004220 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004221 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4222 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004223 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004224 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004225 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004226 if (index >= 0 && index < str->length()) {
4227 Handle<Object> result = GetCharAt(str, index);
4228 return *result;
4229 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004230 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231
4232 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004233 return Runtime::GetObjectProperty(isolate,
4234 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004235 args.at<Object>(1));
4236}
4237
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004238// Implements part of 8.12.9 DefineOwnProperty.
4239// There are 3 cases that lead here:
4240// Step 4b - define a new accessor property.
4241// Steps 9c & 12 - replace an existing data property with an accessor property.
4242// Step 12 - update an existing accessor property with an accessor or generic
4243// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004244RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004245 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004246 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004247 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4248 CONVERT_CHECKED(String, name, args[1]);
4249 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004250 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004251 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004252
ager@chromium.org5c838252010-02-19 08:53:10 +00004253 int unchecked = flag_attr->value();
4254 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004255 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004256
4257 RUNTIME_ASSERT(!obj->IsNull());
4258 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004259 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4260}
4261
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004262// Implements part of 8.12.9 DefineOwnProperty.
4263// There are 3 cases that lead here:
4264// Step 4a - define a new data property.
4265// Steps 9b & 12 - replace an existing accessor property with a data property.
4266// Step 12 - update an existing data property with a data or generic
4267// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004268RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004269 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004271 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4272 CONVERT_ARG_CHECKED(String, name, 1);
4273 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004274 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004275
ager@chromium.org5c838252010-02-19 08:53:10 +00004276 int unchecked = flag->value();
4277 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004278 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4279
4280 // Check if this is an element.
4281 uint32_t index;
4282 bool is_element = name->AsArrayIndex(&index);
4283
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004284 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004285 // If elements are in fast case we always implicitly assume that:
4286 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004287 if (is_element && (attr != NONE ||
4288 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004289 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004290 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004291 // We do not need to do access checks here since these has already
4292 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004293 Handle<Object> proto(js_object->GetPrototype());
4294 // If proxy is detached, ignore the assignment. Alternatively,
4295 // we could throw an exception.
4296 if (proto->IsNull()) return *obj_value;
4297 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004298 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004299
4300 // Don't allow element properties to be redefined on objects with external
4301 // array elements.
4302 if (js_object->HasExternalArrayElements()) {
4303 Handle<Object> args[2] = { js_object, name };
4304 Handle<Object> error =
4305 isolate->factory()->NewTypeError("redef_external_array_element",
4306 HandleVector(args, 2));
4307 return isolate->Throw(*error);
4308 }
4309
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004310 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004311 // Make sure that we never go back to fast case.
4312 dictionary->set_requires_slow_elements();
4313 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004314 Handle<NumberDictionary> extended_dictionary =
4315 NumberDictionarySet(dictionary, index, obj_value, details);
4316 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004317 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004318 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4319 } else {
4320 js_object->set_elements(*extended_dictionary);
4321 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004322 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004323 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004324 }
4325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004326 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004327 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004329 // Special case for callback properties.
4330 if (result.IsProperty() && result.type() == CALLBACKS) {
4331 Object* callback = result.GetCallbackObject();
4332 // To be compatible with Safari we do not change the value on API objects
4333 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4334 // the value.
4335 if (callback->IsAccessorInfo()) {
4336 return isolate->heap()->undefined_value();
4337 }
4338 // Avoid redefining foreign callback as data property, just use the stored
4339 // setter to update the value instead.
4340 // TODO(mstarzinger): So far this only works if property attributes don't
4341 // change, this should be fixed once we cleanup the underlying code.
4342 if (callback->IsForeign() && result.GetAttributes() == attr) {
4343 return js_object->SetPropertyWithCallback(callback,
4344 *name,
4345 *obj_value,
4346 result.holder(),
4347 kStrictMode);
4348 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004349 }
4350
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 // Take special care when attributes are different and there is already
4352 // a property. For simplicity we normalize the property which enables us
4353 // to not worry about changing the instance_descriptor and creating a new
4354 // map. The current version of SetObjectProperty does not handle attributes
4355 // correctly in the case where a property is a field and is reset with
4356 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004357 if (result.IsProperty() &&
4358 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004359 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004360 if (js_object->IsJSGlobalProxy()) {
4361 // Since the result is a property, the prototype will exist so
4362 // we don't have to check for null.
4363 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004364 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004365 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 // Use IgnoreAttributes version since a readonly property may be
4367 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004368 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4369 *obj_value,
4370 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004371 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 return Runtime::ForceSetObjectProperty(isolate,
4374 js_object,
4375 name,
4376 obj_value,
4377 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004378}
4379
4380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004381// Special case for elements if any of the flags are true.
4382// If elements are in fast case we always implicitly assume that:
4383// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4384static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4385 Handle<JSObject> js_object,
4386 uint32_t index,
4387 Handle<Object> value,
4388 PropertyAttributes attr) {
4389 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004390 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004391 // Make sure that we never go back to fast case.
4392 dictionary->set_requires_slow_elements();
4393 PropertyDetails details = PropertyDetails(attr, NORMAL);
4394 Handle<NumberDictionary> extended_dictionary =
4395 NumberDictionarySet(dictionary, index, value, details);
4396 if (*extended_dictionary != *dictionary) {
4397 js_object->set_elements(*extended_dictionary);
4398 }
4399 return *value;
4400}
4401
4402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004403MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4404 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004405 Handle<Object> key,
4406 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004407 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004408 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004412 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 isolate->factory()->NewTypeError("non_object_property_store",
4415 HandleVector(args, 2));
4416 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 }
4418
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004419 if (object->IsJSProxy()) {
4420 bool has_pending_exception = false;
4421 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4422 if (has_pending_exception) return Failure::Exception();
4423 return JSProxy::cast(*object)->SetProperty(
4424 String::cast(*name), *value, attr, strict_mode);
4425 }
4426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 // If the object isn't a JavaScript object, we ignore the store.
4428 if (!object->IsJSObject()) return *value;
4429
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004430 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 // Check if the given key is an array index.
4433 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004434 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4436 // of a string using [] notation. We need to support this too in
4437 // JavaScript.
4438 // In the case of a String object we just need to redirect the assignment to
4439 // the underlying string if the index is in range. Since the underlying
4440 // string does nothing with the assignment then we can ignore such
4441 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004442 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004446 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4447 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4448 }
4449
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004450 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004451 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 return *value;
4453 }
4454
4455 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004456 Handle<Object> result;
4457 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004458 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4459 return NormalizeObjectSetElement(isolate,
4460 js_object,
4461 index,
4462 value,
4463 attr);
4464 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004465 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004467 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004468 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004469 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004471 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 return *value;
4473 }
4474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 bool has_pending_exception = false;
4477 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4478 if (has_pending_exception) return Failure::Exception();
4479 Handle<String> name = Handle<String>::cast(converted);
4480
4481 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004482 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004484 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 }
4486}
4487
4488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4490 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004491 Handle<Object> key,
4492 Handle<Object> value,
4493 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004494 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004495
4496 // Check if the given key is an array index.
4497 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004498 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004499 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4500 // of a string using [] notation. We need to support this too in
4501 // JavaScript.
4502 // In the case of a String object we just need to redirect the assignment to
4503 // the underlying string if the index is in range. Since the underlying
4504 // string does nothing with the assignment then we can ignore such
4505 // assignments.
4506 if (js_object->IsStringObjectWithCharacterAt(index)) {
4507 return *value;
4508 }
4509
whesse@chromium.org7b260152011-06-20 15:33:18 +00004510 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004511 }
4512
4513 if (key->IsString()) {
4514 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004515 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516 } else {
4517 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004518 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004519 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4520 *value,
4521 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004522 }
4523 }
4524
4525 // Call-back into JavaScript to convert the key to a string.
4526 bool has_pending_exception = false;
4527 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4528 if (has_pending_exception) return Failure::Exception();
4529 Handle<String> name = Handle<String>::cast(converted);
4530
4531 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004532 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004534 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004535 }
4536}
4537
4538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004540 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004542 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004543
4544 // Check if the given key is an array index.
4545 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004546 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004547 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4548 // characters of a string using [] notation. In the case of a
4549 // String object we just need to redirect the deletion to the
4550 // underlying string if the index is in range. Since the
4551 // underlying string does nothing with the deletion, we can ignore
4552 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004553 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004555 }
4556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004557 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004558 }
4559
4560 Handle<String> key_string;
4561 if (key->IsString()) {
4562 key_string = Handle<String>::cast(key);
4563 } else {
4564 // Call-back into JavaScript to convert the key to a string.
4565 bool has_pending_exception = false;
4566 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4567 if (has_pending_exception) return Failure::Exception();
4568 key_string = Handle<String>::cast(converted);
4569 }
4570
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004571 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004572 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004573}
4574
4575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004576RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004578 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579
4580 Handle<Object> object = args.at<Object>(0);
4581 Handle<Object> key = args.at<Object>(1);
4582 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004583 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004584 RUNTIME_ASSERT(
4585 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004587 PropertyAttributes attributes =
4588 static_cast<PropertyAttributes>(unchecked_attributes);
4589
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004590 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004591 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004592 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4593 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 return Runtime::SetObjectProperty(isolate,
4597 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004598 key,
4599 value,
4600 attributes,
4601 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602}
4603
4604
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004605RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4606 NoHandleAllocation ha;
4607 RUNTIME_ASSERT(args.length() == 1);
4608 Handle<Object> object = args.at<Object>(0);
4609 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4610}
4611
4612
4613RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4614 NoHandleAllocation ha;
4615 RUNTIME_ASSERT(args.length() == 1);
4616 Handle<Object> object = args.at<Object>(0);
4617 return TransitionElements(object, FAST_ELEMENTS, isolate);
4618}
4619
4620
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004621// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004622// This is used to decide if we should transform null and undefined
4623// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004625 NoHandleAllocation ha;
4626 RUNTIME_ASSERT(args.length() == 1);
4627
4628 Handle<Object> object = args.at<Object>(0);
4629
4630 if (object->IsJSFunction()) {
4631 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004632 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004633 }
4634 return isolate->heap()->undefined_value();
4635}
4636
4637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004638RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4639 RUNTIME_ASSERT(args.length() == 5);
4640 CONVERT_ARG_CHECKED(JSObject, object, 0);
4641 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4642 Handle<Object> value = args.at<Object>(2);
4643 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4644 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4645 HandleScope scope;
4646
4647 Object* raw_boilerplate_object = literals->get(literal_index);
4648 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4649#if DEBUG
4650 ElementsKind elements_kind = object->GetElementsKind();
4651#endif
4652 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4653 // Smis should never trigger transitions.
4654 ASSERT(!value->IsSmi());
4655
4656 if (value->IsNumber()) {
4657 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4658 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004659 TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004660 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4661 FixedDoubleArray* double_array =
4662 FixedDoubleArray::cast(object->elements());
4663 HeapNumber* number = HeapNumber::cast(*value);
4664 double_array->set(store_index, number->Number());
4665 } else {
4666 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4667 elements_kind == FAST_DOUBLE_ELEMENTS);
4668 TransitionElementsKind(object, FAST_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004669 TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670 FixedArray* object_array =
4671 FixedArray::cast(object->elements());
4672 object_array->set(store_index, *value);
4673 }
4674 return *object;
4675}
4676
4677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678// Set a local property, even if it is READ_ONLY. If the property does not
4679// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004680RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004682 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 CONVERT_CHECKED(JSObject, object, args[0]);
4684 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004685 // Compute attributes.
4686 PropertyAttributes attributes = NONE;
4687 if (args.length() == 4) {
4688 CONVERT_CHECKED(Smi, value_obj, args[3]);
4689 int unchecked_value = value_obj->value();
4690 // Only attribute bits should be set.
4691 RUNTIME_ASSERT(
4692 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4693 attributes = static_cast<PropertyAttributes>(unchecked_value);
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004696 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004697 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698}
4699
4700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004701RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004703 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004705 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004707 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4708 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004709 ? JSReceiver::STRICT_DELETION
4710 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711}
4712
4713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714static Object* HasLocalPropertyImplementation(Isolate* isolate,
4715 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004716 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004717 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004718 // Handle hidden prototypes. If there's a hidden prototype above this thing
4719 // then we have to check it for properties, because they are supposed to
4720 // look like they are on this object.
4721 Handle<Object> proto(object->GetPrototype());
4722 if (proto->IsJSObject() &&
4723 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004724 return HasLocalPropertyImplementation(isolate,
4725 Handle<JSObject>::cast(proto),
4726 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004727 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004728 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004729}
4730
4731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
4734 ASSERT(args.length() == 2);
4735 CONVERT_CHECKED(String, key, args[1]);
4736
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004737 uint32_t index;
4738 const bool key_is_array_index = key->AsArrayIndex(&index);
4739
ager@chromium.org9085a012009-05-11 19:22:57 +00004740 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004742 if (obj->IsJSObject()) {
4743 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004744 // Fast case: either the key is a real named property or it is not
4745 // an array index and there are no interceptors or hidden
4746 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004748 Map* map = object->map();
4749 if (!key_is_array_index &&
4750 !map->has_named_interceptor() &&
4751 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4752 return isolate->heap()->false_value();
4753 }
4754 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 HandleScope scope(isolate);
4756 return HasLocalPropertyImplementation(isolate,
4757 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004758 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004759 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004761 String* string = String::cast(obj);
4762 if (index < static_cast<uint32_t>(string->length())) {
4763 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 }
4765 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767}
4768
4769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004770RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 NoHandleAllocation na;
4772 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004773 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4774 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004776 bool result = receiver->HasProperty(key);
4777 if (isolate->has_pending_exception()) return Failure::Exception();
4778 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004782RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 NoHandleAllocation na;
4784 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4786 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004788 bool result = receiver->HasElement(index->value());
4789 if (isolate->has_pending_exception()) return Failure::Exception();
4790 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791}
4792
4793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004794RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 NoHandleAllocation ha;
4796 ASSERT(args.length() == 2);
4797
4798 CONVERT_CHECKED(JSObject, object, args[0]);
4799 CONVERT_CHECKED(String, key, args[1]);
4800
4801 uint32_t index;
4802 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004803 JSObject::LocalElementType type = object->HasLocalElement(index);
4804 switch (type) {
4805 case JSObject::UNDEFINED_ELEMENT:
4806 case JSObject::STRING_CHARACTER_ELEMENT:
4807 return isolate->heap()->false_value();
4808 case JSObject::INTERCEPTED_ELEMENT:
4809 case JSObject::FAST_ELEMENT:
4810 return isolate->heap()->true_value();
4811 case JSObject::DICTIONARY_ELEMENT: {
4812 if (object->IsJSGlobalProxy()) {
4813 Object* proto = object->GetPrototype();
4814 if (proto->IsNull()) {
4815 return isolate->heap()->false_value();
4816 }
4817 ASSERT(proto->IsJSGlobalObject());
4818 object = JSObject::cast(proto);
4819 }
4820 FixedArray* elements = FixedArray::cast(object->elements());
4821 NumberDictionary* dictionary = NULL;
4822 if (elements->map() ==
4823 isolate->heap()->non_strict_arguments_elements_map()) {
4824 dictionary = NumberDictionary::cast(elements->get(1));
4825 } else {
4826 dictionary = NumberDictionary::cast(elements);
4827 }
4828 int entry = dictionary->FindEntry(index);
4829 ASSERT(entry != NumberDictionary::kNotFound);
4830 PropertyDetails details = dictionary->DetailsAt(entry);
4831 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4832 }
4833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 }
4835
ager@chromium.org870a0b62008-11-04 11:43:05 +00004836 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838}
4839
4840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004841RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004842 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004844 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4845 bool threw = false;
4846 Handle<JSArray> result = GetKeysFor(object, &threw);
4847 if (threw) return Failure::Exception();
4848 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849}
4850
4851
4852// Returns either a FixedArray as Runtime_GetPropertyNames,
4853// or, if the given object has an enum cache that contains
4854// all enumerable properties of the object and its prototypes
4855// have none, the map of the object. This is used to speed up
4856// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004857RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 ASSERT(args.length() == 1);
4859
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004860 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861
4862 if (raw_object->IsSimpleEnum()) return raw_object->map();
4863
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004865 Handle<JSReceiver> object(raw_object);
4866 bool threw = false;
4867 Handle<FixedArray> content =
4868 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4869 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870
4871 // Test again, since cache may have been built by preceding call.
4872 if (object->IsSimpleEnum()) return object->map();
4873
4874 return *content;
4875}
4876
4877
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004878// Find the length of the prototype chain that is to to handled as one. If a
4879// prototype object is hidden it is to be viewed as part of the the object it
4880// is prototype for.
4881static int LocalPrototypeChainLength(JSObject* obj) {
4882 int count = 1;
4883 Object* proto = obj->GetPrototype();
4884 while (proto->IsJSObject() &&
4885 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4886 count++;
4887 proto = JSObject::cast(proto)->GetPrototype();
4888 }
4889 return count;
4890}
4891
4892
4893// Return the names of the local named properties.
4894// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004895RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004896 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004897 ASSERT(args.length() == 1);
4898 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004900 }
4901 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4902
4903 // Skip the global proxy as it has no properties and always delegates to the
4904 // real global object.
4905 if (obj->IsJSGlobalProxy()) {
4906 // Only collect names if access is permitted.
4907 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 !isolate->MayNamedAccess(*obj,
4909 isolate->heap()->undefined_value(),
4910 v8::ACCESS_KEYS)) {
4911 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4912 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004913 }
4914 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4915 }
4916
4917 // Find the number of objects making up this.
4918 int length = LocalPrototypeChainLength(*obj);
4919
4920 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004921 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004922 int total_property_count = 0;
4923 Handle<JSObject> jsproto = obj;
4924 for (int i = 0; i < length; i++) {
4925 // Only collect names if access is permitted.
4926 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 !isolate->MayNamedAccess(*jsproto,
4928 isolate->heap()->undefined_value(),
4929 v8::ACCESS_KEYS)) {
4930 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4931 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004932 }
4933 int n;
4934 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4935 local_property_count[i] = n;
4936 total_property_count += n;
4937 if (i < length - 1) {
4938 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4939 }
4940 }
4941
4942 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004943 Handle<FixedArray> names =
4944 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004945
4946 // Get the property names.
4947 jsproto = obj;
4948 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004949 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004950 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004951 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4952 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004953 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004954 proto_with_hidden_properties++;
4955 }
4956 if (i < length - 1) {
4957 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4958 }
4959 }
4960
4961 // Filter out name of hidden propeties object.
4962 if (proto_with_hidden_properties > 0) {
4963 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004964 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 names->length() - proto_with_hidden_properties);
4966 int dest_pos = 0;
4967 for (int i = 0; i < total_property_count; i++) {
4968 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004970 continue;
4971 }
4972 names->set(dest_pos++, name);
4973 }
4974 }
4975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004976 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977}
4978
4979
4980// Return the names of the local indexed properties.
4981// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004982RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004983 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 ASSERT(args.length() == 1);
4985 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004987 }
4988 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4989
4990 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004993 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994}
4995
4996
4997// Return information on whether an object has a named or indexed interceptor.
4998// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004999RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 ASSERT(args.length() == 1);
5002 if (!args[0]->IsJSObject()) {
5003 return Smi::FromInt(0);
5004 }
5005 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5006
5007 int result = 0;
5008 if (obj->HasNamedInterceptor()) result |= 2;
5009 if (obj->HasIndexedInterceptor()) result |= 1;
5010
5011 return Smi::FromInt(result);
5012}
5013
5014
5015// Return property names from named interceptor.
5016// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005018 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019 ASSERT(args.length() == 1);
5020 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5021
5022 if (obj->HasNamedInterceptor()) {
5023 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5024 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5025 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005026 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027}
5028
5029
5030// Return element names from indexed interceptor.
5031// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005032RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005033 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005034 ASSERT(args.length() == 1);
5035 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5036
5037 if (obj->HasIndexedInterceptor()) {
5038 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5039 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5040 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042}
5043
5044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005045RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005046 ASSERT_EQ(args.length(), 1);
5047 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005049 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005050
5051 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005052 // Do access checks before going to the global object.
5053 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005055 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5057 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005058 }
5059
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005060 Handle<Object> proto(object->GetPrototype());
5061 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005063 object = Handle<JSObject>::cast(proto);
5064 }
5065
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005066 bool threw = false;
5067 Handle<FixedArray> contents =
5068 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5069 if (threw) return Failure::Exception();
5070
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005071 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5072 // property array and since the result is mutable we have to create
5073 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005074 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005076 for (int i = 0; i < length; i++) {
5077 Object* entry = contents->get(i);
5078 if (entry->IsString()) {
5079 copy->set(i, entry);
5080 } else {
5081 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 HandleScope scope(isolate);
5083 Handle<Object> entry_handle(entry, isolate);
5084 Handle<Object> entry_str =
5085 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005086 copy->set(i, *entry_str);
5087 }
5088 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005090}
5091
5092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005093RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005094 NoHandleAllocation ha;
5095 ASSERT(args.length() == 1);
5096
5097 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005098 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005099 it.AdvanceToArgumentsFrame();
5100 JavaScriptFrame* frame = it.frame();
5101
5102 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005103 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005104
5105 // Try to convert the key to an index. If successful and within
5106 // index return the the argument from the frame.
5107 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005108 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 return frame->GetParameter(index);
5110 }
5111
5112 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 bool exception = false;
5115 Handle<Object> converted =
5116 Execution::ToString(args.at<Object>(0), &exception);
5117 if (exception) return Failure::Exception();
5118 Handle<String> key = Handle<String>::cast(converted);
5119
5120 // Try to convert the string key into an array index.
5121 if (key->AsArrayIndex(&index)) {
5122 if (index < n) {
5123 return frame->GetParameter(index);
5124 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005125 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 }
5127 }
5128
5129 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005130 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5131 if (key->Equals(isolate->heap()->callee_symbol())) {
5132 Object* function = frame->function();
5133 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005134 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 return isolate->Throw(*isolate->factory()->NewTypeError(
5136 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5137 }
5138 return function;
5139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140
5141 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143}
5144
5145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005146RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005148
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005149 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005150 Handle<Object> object = args.at<Object>(0);
5151 if (object->IsJSObject()) {
5152 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005153 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005154 MaybeObject* ok = js_object->TransformToFastProperties(0);
5155 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005156 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005157 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005158 return *object;
5159}
5160
5161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005162RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005163 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005164
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005165 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005166 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005167 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005168 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005169 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005170 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005171 return *object;
5172}
5173
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 NoHandleAllocation ha;
5177 ASSERT(args.length() == 1);
5178
5179 return args[0]->ToBoolean();
5180}
5181
5182
5183// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5184// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005185RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 NoHandleAllocation ha;
5187
5188 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005189 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 HeapObject* heap_obj = HeapObject::cast(obj);
5191
5192 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 if (heap_obj->map()->is_undetectable()) {
5194 return isolate->heap()->undefined_symbol();
5195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196
5197 InstanceType instance_type = heap_obj->map()->instance_type();
5198 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200 }
5201
5202 switch (instance_type) {
5203 case ODDBALL_TYPE:
5204 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 }
5207 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005208 return FLAG_harmony_typeof
5209 ? isolate->heap()->null_symbol()
5210 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 }
5212 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005214 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005215 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005217 default:
5218 // For any kind of object not handled above, the spec rule for
5219 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005220 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 }
5222}
5223
5224
lrn@chromium.org25156de2010-04-06 13:10:27 +00005225static bool AreDigits(const char*s, int from, int to) {
5226 for (int i = from; i < to; i++) {
5227 if (s[i] < '0' || s[i] > '9') return false;
5228 }
5229
5230 return true;
5231}
5232
5233
5234static int ParseDecimalInteger(const char*s, int from, int to) {
5235 ASSERT(to - from < 10); // Overflow is not possible.
5236 ASSERT(from < to);
5237 int d = s[from] - '0';
5238
5239 for (int i = from + 1; i < to; i++) {
5240 d = 10 * d + (s[i] - '0');
5241 }
5242
5243 return d;
5244}
5245
5246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005247RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 NoHandleAllocation ha;
5249 ASSERT(args.length() == 1);
5250 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005251 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005252
5253 // Fast case: short integer or some sorts of junk values.
5254 int len = subject->length();
5255 if (subject->IsSeqAsciiString()) {
5256 if (len == 0) return Smi::FromInt(0);
5257
5258 char const* data = SeqAsciiString::cast(subject)->GetChars();
5259 bool minus = (data[0] == '-');
5260 int start_pos = (minus ? 1 : 0);
5261
5262 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264 } else if (data[start_pos] > '9') {
5265 // Fast check for a junk value. A valid string may start from a
5266 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5267 // the 'I' character ('Infinity'). All of that have codes not greater than
5268 // '9' except 'I'.
5269 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005271 }
5272 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5273 // The maximal/minimal smi has 10 digits. If the string has less digits we
5274 // know it will fit into the smi-data type.
5275 int d = ParseDecimalInteger(data, start_pos, len);
5276 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005277 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005278 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005279 } else if (!subject->HasHashCode() &&
5280 len <= String::kMaxArrayIndexSize &&
5281 (len == 1 || data[0] != '0')) {
5282 // String hash is not calculated yet but all the data are present.
5283 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005284 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005285#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005286 subject->Hash(); // Force hash calculation.
5287 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5288 static_cast<int>(hash));
5289#endif
5290 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005291 }
5292 return Smi::FromInt(d);
5293 }
5294 }
5295
5296 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005297 return isolate->heap()->NumberFromDouble(
5298 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005299}
5300
5301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005302RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005303 NoHandleAllocation ha;
5304 ASSERT(args.length() == 1);
5305
5306 CONVERT_CHECKED(JSArray, codes, args[0]);
5307 int length = Smi::cast(codes->length())->value();
5308
5309 // Check if the string can be ASCII.
5310 int i;
5311 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005312 Object* element;
5313 { MaybeObject* maybe_element = codes->GetElement(i);
5314 // We probably can't get an exception here, but just in order to enforce
5315 // the checking of inputs in the runtime calls we check here.
5316 if (!maybe_element->ToObject(&element)) return maybe_element;
5317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5319 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5320 break;
5321 }
5322
lrn@chromium.org303ada72010-10-27 09:33:13 +00005323 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005325 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005327 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005328 }
5329
lrn@chromium.org303ada72010-10-27 09:33:13 +00005330 Object* object = NULL;
5331 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005332 String* result = String::cast(object);
5333 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005334 Object* element;
5335 { MaybeObject* maybe_element = codes->GetElement(i);
5336 if (!maybe_element->ToObject(&element)) return maybe_element;
5337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005339 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
5341 return result;
5342}
5343
5344
5345// kNotEscaped is generated by the following:
5346//
5347// #!/bin/perl
5348// for (my $i = 0; $i < 256; $i++) {
5349// print "\n" if $i % 16 == 0;
5350// my $c = chr($i);
5351// my $escaped = 1;
5352// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5353// print $escaped ? "0, " : "1, ";
5354// }
5355
5356
5357static bool IsNotEscaped(uint16_t character) {
5358 // Only for 8 bit characters, the rest are always escaped (in a different way)
5359 ASSERT(character < 256);
5360 static const char kNotEscaped[256] = {
5361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5367 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5377 };
5378 return kNotEscaped[character] != 0;
5379}
5380
5381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005382RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 const char hex_chars[] = "0123456789ABCDEF";
5384 NoHandleAllocation ha;
5385 ASSERT(args.length() == 1);
5386 CONVERT_CHECKED(String, source, args[0]);
5387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005388 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389
5390 int escaped_length = 0;
5391 int length = source->length();
5392 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005393 Access<StringInputBuffer> buffer(
5394 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 buffer->Reset(source);
5396 while (buffer->has_more()) {
5397 uint16_t character = buffer->GetNext();
5398 if (character >= 256) {
5399 escaped_length += 6;
5400 } else if (IsNotEscaped(character)) {
5401 escaped_length++;
5402 } else {
5403 escaped_length += 3;
5404 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005405 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005406 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005407 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005408 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 return Failure::OutOfMemoryException();
5410 }
5411 }
5412 }
5413 // No length change implies no change. Return original string if no change.
5414 if (escaped_length == length) {
5415 return source;
5416 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005417 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005418 { MaybeObject* maybe_o =
5419 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 if (!maybe_o->ToObject(&o)) return maybe_o;
5421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005422 String* destination = String::cast(o);
5423 int dest_position = 0;
5424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 Access<StringInputBuffer> buffer(
5426 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 buffer->Rewind();
5428 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005429 uint16_t chr = buffer->GetNext();
5430 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 destination->Set(dest_position, '%');
5432 destination->Set(dest_position+1, 'u');
5433 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5434 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5435 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5436 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005438 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005440 dest_position++;
5441 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005442 destination->Set(dest_position, '%');
5443 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5444 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 dest_position += 3;
5446 }
5447 }
5448 return destination;
5449}
5450
5451
5452static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5453 static const signed char kHexValue['g'] = {
5454 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5455 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5456 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5457 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5458 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5459 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5460 -1, 10, 11, 12, 13, 14, 15 };
5461
5462 if (character1 > 'f') return -1;
5463 int hi = kHexValue[character1];
5464 if (hi == -1) return -1;
5465 if (character2 > 'f') return -1;
5466 int lo = kHexValue[character2];
5467 if (lo == -1) return -1;
5468 return (hi << 4) + lo;
5469}
5470
5471
ager@chromium.org870a0b62008-11-04 11:43:05 +00005472static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005473 int i,
5474 int length,
5475 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005477 int32_t hi = 0;
5478 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 if (character == '%' &&
5480 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 source->Get(i + 1) == 'u' &&
5482 (hi = TwoDigitHex(source->Get(i + 2),
5483 source->Get(i + 3))) != -1 &&
5484 (lo = TwoDigitHex(source->Get(i + 4),
5485 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 *step = 6;
5487 return (hi << 8) + lo;
5488 } else if (character == '%' &&
5489 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005490 (lo = TwoDigitHex(source->Get(i + 1),
5491 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 *step = 3;
5493 return lo;
5494 } else {
5495 *step = 1;
5496 return character;
5497 }
5498}
5499
5500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005501RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 NoHandleAllocation ha;
5503 ASSERT(args.length() == 1);
5504 CONVERT_CHECKED(String, source, args[0]);
5505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005506 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507
5508 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510
5511 int unescaped_length = 0;
5512 for (int i = 0; i < length; unescaped_length++) {
5513 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005514 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 i += step;
5518 }
5519
5520 // No length change implies no change. Return original string if no change.
5521 if (unescaped_length == length)
5522 return source;
5523
lrn@chromium.org303ada72010-10-27 09:33:13 +00005524 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005525 { MaybeObject* maybe_o =
5526 ascii ?
5527 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5528 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529 if (!maybe_o->ToObject(&o)) return maybe_o;
5530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 String* destination = String::cast(o);
5532
5533 int dest_position = 0;
5534 for (int i = 0; i < length; dest_position++) {
5535 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 i += step;
5538 }
5539 return destination;
5540}
5541
5542
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005543static const unsigned int kQuoteTableLength = 128u;
5544
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545static const int kJsonQuotesCharactersPerEntry = 8;
5546static const char* const JsonQuotes =
5547 "\\u0000 \\u0001 \\u0002 \\u0003 "
5548 "\\u0004 \\u0005 \\u0006 \\u0007 "
5549 "\\b \\t \\n \\u000b "
5550 "\\f \\r \\u000e \\u000f "
5551 "\\u0010 \\u0011 \\u0012 \\u0013 "
5552 "\\u0014 \\u0015 \\u0016 \\u0017 "
5553 "\\u0018 \\u0019 \\u001a \\u001b "
5554 "\\u001c \\u001d \\u001e \\u001f "
5555 " ! \\\" # "
5556 "$ % & ' "
5557 "( ) * + "
5558 ", - . / "
5559 "0 1 2 3 "
5560 "4 5 6 7 "
5561 "8 9 : ; "
5562 "< = > ? "
5563 "@ A B C "
5564 "D E F G "
5565 "H I J K "
5566 "L M N O "
5567 "P Q R S "
5568 "T U V W "
5569 "X Y Z [ "
5570 "\\\\ ] ^ _ "
5571 "` a b c "
5572 "d e f g "
5573 "h i j k "
5574 "l m n o "
5575 "p q r s "
5576 "t u v w "
5577 "x y z { "
5578 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005579
5580
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005581// For a string that is less than 32k characters it should always be
5582// possible to allocate it in new space.
5583static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5584
5585
5586// Doing JSON quoting cannot make the string more than this many times larger.
5587static const int kJsonQuoteWorstCaseBlowup = 6;
5588
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005589static const int kSpaceForQuotesAndComma = 3;
5590static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005591
5592// Covers the entire ASCII range (all other characters are unchanged by JSON
5593// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005594static const byte JsonQuoteLengths[kQuoteTableLength] = {
5595 6, 6, 6, 6, 6, 6, 6, 6,
5596 2, 2, 2, 6, 2, 2, 6, 6,
5597 6, 6, 6, 6, 6, 6, 6, 6,
5598 6, 6, 6, 6, 6, 6, 6, 6,
5599 1, 1, 2, 1, 1, 1, 1, 1,
5600 1, 1, 1, 1, 1, 1, 1, 1,
5601 1, 1, 1, 1, 1, 1, 1, 1,
5602 1, 1, 1, 1, 1, 1, 1, 1,
5603 1, 1, 1, 1, 1, 1, 1, 1,
5604 1, 1, 1, 1, 1, 1, 1, 1,
5605 1, 1, 1, 1, 1, 1, 1, 1,
5606 1, 1, 1, 1, 2, 1, 1, 1,
5607 1, 1, 1, 1, 1, 1, 1, 1,
5608 1, 1, 1, 1, 1, 1, 1, 1,
5609 1, 1, 1, 1, 1, 1, 1, 1,
5610 1, 1, 1, 1, 1, 1, 1, 1,
5611};
5612
5613
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005615MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005616
5617
5618template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5620 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005621}
5622
5623
5624template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005625MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5626 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005627}
5628
5629
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005630template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5632 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005634 const Char* read_cursor = characters.start();
5635 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005636 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005637 int quoted_length = kSpaceForQuotes;
5638 while (read_cursor < end) {
5639 Char c = *(read_cursor++);
5640 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5641 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005642 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644 }
5645 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005646 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5647 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005648 Object* new_object;
5649 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005650 return new_alloc;
5651 }
5652 StringType* new_string = StringType::cast(new_object);
5653
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005654 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005655 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005656 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005657 *(write_cursor++) = '"';
5658
5659 read_cursor = characters.start();
5660 while (read_cursor < end) {
5661 Char c = *(read_cursor++);
5662 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5663 *(write_cursor++) = c;
5664 } else {
5665 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5666 const char* replacement = JsonQuotes +
5667 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5668 for (int i = 0; i < len; i++) {
5669 *write_cursor++ = *replacement++;
5670 }
5671 }
5672 }
5673 *(write_cursor++) = '"';
5674 return new_string;
5675}
5676
5677
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005678template <typename SinkChar, typename SourceChar>
5679static inline SinkChar* WriteQuoteJsonString(
5680 Isolate* isolate,
5681 SinkChar* write_cursor,
5682 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005683 // SinkChar is only char if SourceChar is guaranteed to be char.
5684 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005685 const SourceChar* read_cursor = characters.start();
5686 const SourceChar* end = read_cursor + characters.length();
5687 *(write_cursor++) = '"';
5688 while (read_cursor < end) {
5689 SourceChar c = *(read_cursor++);
5690 if (sizeof(SourceChar) > 1u &&
5691 static_cast<unsigned>(c) >= kQuoteTableLength) {
5692 *(write_cursor++) = static_cast<SinkChar>(c);
5693 } else {
5694 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5695 const char* replacement = JsonQuotes +
5696 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5697 write_cursor[0] = replacement[0];
5698 if (len > 1) {
5699 write_cursor[1] = replacement[1];
5700 if (len > 2) {
5701 ASSERT(len == 6);
5702 write_cursor[2] = replacement[2];
5703 write_cursor[3] = replacement[3];
5704 write_cursor[4] = replacement[4];
5705 write_cursor[5] = replacement[5];
5706 }
5707 }
5708 write_cursor += len;
5709 }
5710 }
5711 *(write_cursor++) = '"';
5712 return write_cursor;
5713}
5714
5715
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005716template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717static MaybeObject* QuoteJsonString(Isolate* isolate,
5718 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005719 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005721 int worst_case_length =
5722 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005723 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005724 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005725 }
5726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005727 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5728 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005729 Object* new_object;
5730 if (!new_alloc->ToObject(&new_object)) {
5731 return new_alloc;
5732 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005734 // Even if our string is small enough to fit in new space we still have to
5735 // handle it being allocated in old space as may happen in the third
5736 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5737 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005738 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 }
5740 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005741 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005742
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005743 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005744 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005745 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005746 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5747 write_cursor,
5748 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005749 int final_length = static_cast<int>(
5750 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005751 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005752 isolate->heap()->new_space()->
5753 template ShrinkStringAtAllocationBoundary<StringType>(
5754 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 return new_string;
5756}
5757
5758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005759RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005760 NoHandleAllocation ha;
5761 CONVERT_CHECKED(String, str, args[0]);
5762 if (!str->IsFlat()) {
5763 MaybeObject* try_flatten = str->TryFlatten();
5764 Object* flat;
5765 if (!try_flatten->ToObject(&flat)) {
5766 return try_flatten;
5767 }
5768 str = String::cast(flat);
5769 ASSERT(str->IsFlat());
5770 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005771 String::FlatContent flat = str->GetFlatContent();
5772 ASSERT(flat.IsFlat());
5773 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005775 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005776 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005777 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005778 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005779 }
5780}
5781
5782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005783RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005784 NoHandleAllocation ha;
5785 CONVERT_CHECKED(String, str, args[0]);
5786 if (!str->IsFlat()) {
5787 MaybeObject* try_flatten = str->TryFlatten();
5788 Object* flat;
5789 if (!try_flatten->ToObject(&flat)) {
5790 return try_flatten;
5791 }
5792 str = String::cast(flat);
5793 ASSERT(str->IsFlat());
5794 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005795 String::FlatContent flat = str->GetFlatContent();
5796 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005798 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005799 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005800 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005801 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005802 }
5803}
5804
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005805
5806template <typename Char, typename StringType>
5807static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5808 FixedArray* array,
5809 int worst_case_length) {
5810 int length = array->length();
5811
5812 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5813 worst_case_length);
5814 Object* new_object;
5815 if (!new_alloc->ToObject(&new_object)) {
5816 return new_alloc;
5817 }
5818 if (!isolate->heap()->new_space()->Contains(new_object)) {
5819 // Even if our string is small enough to fit in new space we still have to
5820 // handle it being allocated in old space as may happen in the third
5821 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5822 // CEntryStub::GenerateCore.
5823 return isolate->heap()->undefined_value();
5824 }
5825 AssertNoAllocation no_gc;
5826 StringType* new_string = StringType::cast(new_object);
5827 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5828
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005829 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005830 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005831 *(write_cursor++) = '[';
5832 for (int i = 0; i < length; i++) {
5833 if (i != 0) *(write_cursor++) = ',';
5834 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005835 String::FlatContent content = str->GetFlatContent();
5836 ASSERT(content.IsFlat());
5837 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005838 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5839 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005840 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005841 } else {
5842 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5843 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005844 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005845 }
5846 }
5847 *(write_cursor++) = ']';
5848
5849 int final_length = static_cast<int>(
5850 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005851 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005852 isolate->heap()->new_space()->
5853 template ShrinkStringAtAllocationBoundary<StringType>(
5854 new_string, final_length);
5855 return new_string;
5856}
5857
5858
5859RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5860 NoHandleAllocation ha;
5861 ASSERT(args.length() == 1);
5862 CONVERT_CHECKED(JSArray, array, args[0]);
5863
5864 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5865 FixedArray* elements = FixedArray::cast(array->elements());
5866 int n = elements->length();
5867 bool ascii = true;
5868 int total_length = 0;
5869
5870 for (int i = 0; i < n; i++) {
5871 Object* elt = elements->get(i);
5872 if (!elt->IsString()) return isolate->heap()->undefined_value();
5873 String* element = String::cast(elt);
5874 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5875 total_length += element->length();
5876 if (ascii && element->IsTwoByteRepresentation()) {
5877 ascii = false;
5878 }
5879 }
5880
5881 int worst_case_length =
5882 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5883 + total_length * kJsonQuoteWorstCaseBlowup;
5884
5885 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5886 return isolate->heap()->undefined_value();
5887 }
5888
5889 if (ascii) {
5890 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5891 elements,
5892 worst_case_length);
5893 } else {
5894 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5895 elements,
5896 worst_case_length);
5897 }
5898}
5899
5900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005901RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902 NoHandleAllocation ha;
5903
5904 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005905 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005907 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908
lrn@chromium.org25156de2010-04-06 13:10:27 +00005909 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005910 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 NoHandleAllocation ha;
5917 CONVERT_CHECKED(String, str, args[0]);
5918
5919 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005920 double value = StringToDouble(isolate->unicode_cache(),
5921 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922
5923 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005924 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925}
5926
5927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005931 String* s,
5932 int length,
5933 int input_string_length,
5934 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005935 // We try this twice, once with the assumption that the result is no longer
5936 // than the input and, if that assumption breaks, again with the exact
5937 // length. This may not be pretty, but it is nicer than what was here before
5938 // and I hereby claim my vaffel-is.
5939 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 // Allocate the resulting string.
5941 //
5942 // NOTE: This assumes that the upper/lower case of an ascii
5943 // character is also ascii. This is currently the case, but it
5944 // might break in the future if we implement more context and locale
5945 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005946 Object* o;
5947 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005948 ? isolate->heap()->AllocateRawAsciiString(length)
5949 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005950 if (!maybe_o->ToObject(&o)) return maybe_o;
5951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 String* result = String::cast(o);
5953 bool has_changed_character = false;
5954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005955 // Convert all characters to upper case, assuming that they will fit
5956 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005957 Access<StringInputBuffer> buffer(
5958 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005960 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 // We can assume that the string is not empty
5962 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005963 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005964 bool has_next = buffer->has_more();
5965 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 int char_length = mapping->get(current, next, chars);
5967 if (char_length == 0) {
5968 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005969 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 i++;
5971 } else if (char_length == 1) {
5972 // Common case: converting the letter resulted in one character.
5973 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005974 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 has_changed_character = true;
5976 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005977 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 // We've assumed that the result would be as long as the
5979 // input but here is a character that converts to several
5980 // characters. No matter, we calculate the exact length
5981 // of the result and try the whole thing again.
5982 //
5983 // Note that this leaves room for optimization. We could just
5984 // memcpy what we already have to the result string. Also,
5985 // the result string is the last object allocated we could
5986 // "realloc" it and probably, in the vast majority of cases,
5987 // extend the existing string to be able to hold the full
5988 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005989 int next_length = 0;
5990 if (has_next) {
5991 next_length = mapping->get(next, 0, chars);
5992 if (next_length == 0) next_length = 1;
5993 }
5994 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 while (buffer->has_more()) {
5996 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005997 // NOTE: we use 0 as the next character here because, while
5998 // the next character may affect what a character converts to,
5999 // it does not in any case affect the length of what it convert
6000 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 int char_length = mapping->get(current, 0, chars);
6002 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006003 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006004 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006005 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006006 return Failure::OutOfMemoryException();
6007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006009 // Try again with the real length.
6010 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 } else {
6012 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006013 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 i++;
6015 }
6016 has_changed_character = true;
6017 }
6018 current = next;
6019 }
6020 if (has_changed_character) {
6021 return result;
6022 } else {
6023 // If we didn't actually change anything in doing the conversion
6024 // we simple return the result and let the converted string
6025 // become garbage; there is no reason to keep two identical strings
6026 // alive.
6027 return s;
6028 }
6029}
6030
6031
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006032namespace {
6033
lrn@chromium.org303ada72010-10-27 09:33:13 +00006034static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6035
6036
6037// Given a word and two range boundaries returns a word with high bit
6038// set in every byte iff the corresponding input byte was strictly in
6039// the range (m, n). All the other bits in the result are cleared.
6040// This function is only useful when it can be inlined and the
6041// boundaries are statically known.
6042// Requires: all bytes in the input word and the boundaries must be
6043// ascii (less than 0x7F).
6044static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6045 // Every byte in an ascii string is less than or equal to 0x7F.
6046 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6047 // Use strict inequalities since in edge cases the function could be
6048 // further simplified.
6049 ASSERT(0 < m && m < n && n < 0x7F);
6050 // Has high bit set in every w byte less than n.
6051 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6052 // Has high bit set in every w byte greater than m.
6053 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6054 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6055}
6056
6057
6058enum AsciiCaseConversion {
6059 ASCII_TO_LOWER,
6060 ASCII_TO_UPPER
6061};
6062
6063
6064template <AsciiCaseConversion dir>
6065struct FastAsciiConverter {
6066 static bool Convert(char* dst, char* src, int length) {
6067#ifdef DEBUG
6068 char* saved_dst = dst;
6069 char* saved_src = src;
6070#endif
6071 // We rely on the distance between upper and lower case letters
6072 // being a known power of 2.
6073 ASSERT('a' - 'A' == (1 << 5));
6074 // Boundaries for the range of input characters than require conversion.
6075 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6076 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6077 bool changed = false;
6078 char* const limit = src + length;
6079#ifdef V8_HOST_CAN_READ_UNALIGNED
6080 // Process the prefix of the input that requires no conversion one
6081 // (machine) word at a time.
6082 while (src <= limit - sizeof(uintptr_t)) {
6083 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6084 if (AsciiRangeMask(w, lo, hi) != 0) {
6085 changed = true;
6086 break;
6087 }
6088 *reinterpret_cast<uintptr_t*>(dst) = w;
6089 src += sizeof(uintptr_t);
6090 dst += sizeof(uintptr_t);
6091 }
6092 // Process the remainder of the input performing conversion when
6093 // required one word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 uintptr_t m = AsciiRangeMask(w, lo, hi);
6097 // The mask has high (7th) bit set in every byte that needs
6098 // conversion and we know that the distance between cases is
6099 // 1 << 5.
6100 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104#endif
6105 // Process the last few bytes of the input (or the whole input if
6106 // unaligned access is not supported).
6107 while (src < limit) {
6108 char c = *src;
6109 if (lo < c && c < hi) {
6110 c ^= (1 << 5);
6111 changed = true;
6112 }
6113 *dst = c;
6114 ++src;
6115 ++dst;
6116 }
6117#ifdef DEBUG
6118 CheckConvert(saved_dst, saved_src, length, changed);
6119#endif
6120 return changed;
6121 }
6122
6123#ifdef DEBUG
6124 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6125 bool expected_changed = false;
6126 for (int i = 0; i < length; i++) {
6127 if (dst[i] == src[i]) continue;
6128 expected_changed = true;
6129 if (dir == ASCII_TO_LOWER) {
6130 ASSERT('A' <= src[i] && src[i] <= 'Z');
6131 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6132 } else {
6133 ASSERT(dir == ASCII_TO_UPPER);
6134 ASSERT('a' <= src[i] && src[i] <= 'z');
6135 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6136 }
6137 }
6138 ASSERT(expected_changed == changed);
6139 }
6140#endif
6141};
6142
6143
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006144struct ToLowerTraits {
6145 typedef unibrow::ToLowercase UnibrowConverter;
6146
lrn@chromium.org303ada72010-10-27 09:33:13 +00006147 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148};
6149
6150
6151struct ToUpperTraits {
6152 typedef unibrow::ToUppercase UnibrowConverter;
6153
lrn@chromium.org303ada72010-10-27 09:33:13 +00006154 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155};
6156
6157} // namespace
6158
6159
6160template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006161MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006162 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006163 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006165 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006166 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006167 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006168
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006169 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006170 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 if (length == 0) return s;
6172
6173 // Simpler handling of ascii strings.
6174 //
6175 // NOTE: This assumes that the upper/lower case of an ascii
6176 // character is also ascii. This is currently the case, but it
6177 // might break in the future if we implement more context and locale
6178 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006182 if (!maybe_o->ToObject(&o)) return maybe_o;
6183 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006185 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006186 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 return has_changed_character ? result : s;
6188 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 { MaybeObject* maybe_answer =
6192 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6194 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006195 if (answer->IsSmi()) {
6196 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006197 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 ConvertCaseHelper(isolate,
6199 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006202 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006204}
6205
6206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006207RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return ConvertCase<ToLowerTraits>(
6209 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006213RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006214 return ConvertCase<ToUpperTraits>(
6215 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216}
6217
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006219static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006220 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006221}
6222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006225 NoHandleAllocation ha;
6226 ASSERT(args.length() == 3);
6227
6228 CONVERT_CHECKED(String, s, args[0]);
6229 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6230 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6231
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233 int length = s->length();
6234
6235 int left = 0;
6236 if (trimLeft) {
6237 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6238 left++;
6239 }
6240 }
6241
6242 int right = length;
6243 if (trimRight) {
6244 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6245 right--;
6246 }
6247 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006248 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006249}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006252RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006254 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006255 CONVERT_ARG_CHECKED(String, subject, 0);
6256 CONVERT_ARG_CHECKED(String, pattern, 1);
6257 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6258
6259 int subject_length = subject->length();
6260 int pattern_length = pattern->length();
6261 RUNTIME_ASSERT(pattern_length > 0);
6262
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006263 if (limit == 0xffffffffu) {
6264 Handle<Object> cached_answer(StringSplitCache::Lookup(
6265 isolate->heap()->string_split_cache(),
6266 *subject,
6267 *pattern));
6268 if (*cached_answer != Smi::FromInt(0)) {
6269 Handle<JSArray> result =
6270 isolate->factory()->NewJSArrayWithElements(
6271 Handle<FixedArray>::cast(cached_answer));
6272 return *result;
6273 }
6274 }
6275
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006276 // The limit can be very large (0xffffffffu), but since the pattern
6277 // isn't empty, we can never create more parts than ~half the length
6278 // of the subject.
6279
6280 if (!subject->IsFlat()) FlattenString(subject);
6281
6282 static const int kMaxInitialListCapacity = 16;
6283
danno@chromium.org40cb8782011-05-25 07:58:50 +00006284 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006285
6286 // Find (up to limit) indices of separator and end-of-string in subject
6287 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6288 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006289 if (!pattern->IsFlat()) FlattenString(pattern);
6290
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006291 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006292
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006293 if (static_cast<uint32_t>(indices.length()) < limit) {
6294 indices.Add(subject_length);
6295 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006296
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006297 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006298
6299 // Create JSArray of substrings separated by separator.
6300 int part_count = indices.length();
6301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006302 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006303 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006304 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 result->set_length(Smi::FromInt(part_count));
6306
6307 ASSERT(result->HasFastElements());
6308
6309 if (part_count == 1 && indices.at(0) == subject_length) {
6310 FixedArray::cast(result->elements())->set(0, *subject);
6311 return *result;
6312 }
6313
6314 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6315 int part_start = 0;
6316 for (int i = 0; i < part_count; i++) {
6317 HandleScope local_loop_handle;
6318 int part_end = indices.at(i);
6319 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006320 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 elements->set(i, *substring);
6322 part_start = part_end + pattern_length;
6323 }
6324
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006325 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006326 if (result->HasFastElements()) {
6327 StringSplitCache::Enter(isolate->heap(),
6328 isolate->heap()->string_split_cache(),
6329 *subject,
6330 *pattern,
6331 *elements);
6332 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006333 }
6334
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006335 return *result;
6336}
6337
6338
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339// Copies ascii characters to the given fixed array looking up
6340// one-char strings in the cache. Gives up on the first char that is
6341// not in the cache and fills the remainder with smi zeros. Returns
6342// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343static int CopyCachedAsciiCharsToArray(Heap* heap,
6344 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006345 FixedArray* elements,
6346 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006347 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006348 FixedArray* ascii_cache = heap->single_character_string_cache();
6349 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006350 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006351 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006352 for (i = 0; i < length; ++i) {
6353 Object* value = ascii_cache->get(chars[i]);
6354 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006355 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006356 }
6357 if (i < length) {
6358 ASSERT(Smi::FromInt(0) == 0);
6359 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6360 }
6361#ifdef DEBUG
6362 for (int j = 0; j < length; ++j) {
6363 Object* element = elements->get(j);
6364 ASSERT(element == Smi::FromInt(0) ||
6365 (element->IsString() && String::cast(element)->LooksValid()));
6366 }
6367#endif
6368 return i;
6369}
6370
6371
6372// Converts a String to JSArray.
6373// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006374RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006376 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006377 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006378 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006380 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006381 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006382
6383 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006384 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006385 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006386 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006387 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006388 { MaybeObject* maybe_obj =
6389 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006390 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6391 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006392 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006393 String::FlatContent content = s->GetFlatContent();
6394 if (content.IsAscii()) {
6395 Vector<const char> chars = content.ToAsciiVector();
6396 // Note, this will initialize all elements (not only the prefix)
6397 // to prevent GC from seeing partially initialized array.
6398 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6399 chars.start(),
6400 *elements,
6401 length);
6402 } else {
6403 MemsetPointer(elements->data_start(),
6404 isolate->heap()->undefined_value(),
6405 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006406 }
6407 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006409 }
6410 for (int i = position; i < length; ++i) {
6411 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6412 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006413 }
6414
6415#ifdef DEBUG
6416 for (int i = 0; i < length; ++i) {
6417 ASSERT(String::cast(elements->get(i))->length() == 1);
6418 }
6419#endif
6420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422}
6423
6424
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006425RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006426 NoHandleAllocation ha;
6427 ASSERT(args.length() == 1);
6428 CONVERT_CHECKED(String, value, args[0]);
6429 return value->ToObject();
6430}
6431
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006434 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006436 return char_length == 0;
6437}
6438
6439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006440RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 NoHandleAllocation ha;
6442 ASSERT(args.length() == 1);
6443
6444 Object* number = args[0];
6445 RUNTIME_ASSERT(number->IsNumber());
6446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448}
6449
6450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006451RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006452 NoHandleAllocation ha;
6453 ASSERT(args.length() == 1);
6454
6455 Object* number = args[0];
6456 RUNTIME_ASSERT(number->IsNumber());
6457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
6465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006466 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006467
6468 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6469 if (number > 0 && number <= Smi::kMaxValue) {
6470 return Smi::FromInt(static_cast<int>(number));
6471 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006473}
6474
6475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006476RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 1);
6479
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006480 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006481
6482 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6483 if (number > 0 && number <= Smi::kMaxValue) {
6484 return Smi::FromInt(static_cast<int>(number));
6485 }
6486
6487 double double_value = DoubleToInteger(number);
6488 // Map both -0 and +0 to +0.
6489 if (double_value == 0) double_value = 0;
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006499 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501}
6502
6503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 1);
6507
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006508 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006509
6510 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6511 if (number > 0 && number <= Smi::kMaxValue) {
6512 return Smi::FromInt(static_cast<int>(number));
6513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
ager@chromium.org870a0b62008-11-04 11:43:05 +00006518// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6519// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006521 NoHandleAllocation ha;
6522 ASSERT(args.length() == 1);
6523
6524 Object* obj = args[0];
6525 if (obj->IsSmi()) {
6526 return obj;
6527 }
6528 if (obj->IsHeapNumber()) {
6529 double value = HeapNumber::cast(obj)->value();
6530 int int_value = FastD2I(value);
6531 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6532 return Smi::FromInt(int_value);
6533 }
6534 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006535 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006536}
6537
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006539RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006540 NoHandleAllocation ha;
6541 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 2);
6549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006550 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6551 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006556RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557 NoHandleAllocation ha;
6558 ASSERT(args.length() == 2);
6559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006560 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6561 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563}
6564
6565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006570 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6571 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573}
6574
6575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006576RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 NoHandleAllocation ha;
6578 ASSERT(args.length() == 1);
6579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006580 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 0);
6588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006590}
6591
6592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006593RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 2);
6596
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006597 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6598 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
6606
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006607 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6608 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609
ager@chromium.org3811b432009-10-28 14:53:37 +00006610 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006611 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613}
6614
6615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006616RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 CONVERT_CHECKED(String, str1, args[0]);
6620 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 isolate->counters()->string_add_runtime()->Increment();
6622 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006626template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006627static inline void StringBuilderConcatHelper(String* special,
6628 sinkchar* sink,
6629 FixedArray* fixed_array,
6630 int array_length) {
6631 int position = 0;
6632 for (int i = 0; i < array_length; i++) {
6633 Object* element = fixed_array->get(i);
6634 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006635 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006636 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006637 int pos;
6638 int len;
6639 if (encoded_slice > 0) {
6640 // Position and length encoded in one smi.
6641 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6642 len = StringBuilderSubstringLength::decode(encoded_slice);
6643 } else {
6644 // Position and length encoded in two smis.
6645 Object* obj = fixed_array->get(++i);
6646 ASSERT(obj->IsSmi());
6647 pos = Smi::cast(obj)->value();
6648 len = -encoded_slice;
6649 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006650 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006651 sink + position,
6652 pos,
6653 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006654 position += len;
6655 } else {
6656 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006657 int element_length = string->length();
6658 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006659 position += element_length;
6660 }
6661 }
6662}
6663
6664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006667 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006669 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006671 return Failure::OutOfMemoryException();
6672 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006673 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006674 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006675
6676 // This assumption is used by the slice encoding in one or two smis.
6677 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6678
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006679 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006680 if (maybe_result->IsFailure()) return maybe_result;
6681
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006682 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006684 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 }
6686 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006687 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690
6691 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 } else if (array_length == 1) {
6694 Object* first = fixed_array->get(0);
6695 if (first->IsString()) return first;
6696 }
6697
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006698 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 int position = 0;
6700 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006701 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 Object* elt = fixed_array->get(i);
6703 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006705 int smi_value = Smi::cast(elt)->value();
6706 int pos;
6707 int len;
6708 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006709 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006710 pos = StringBuilderSubstringPosition::decode(smi_value);
6711 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006712 } else {
6713 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006714 len = -smi_value;
6715 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006716 i++;
6717 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006719 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006720 Object* next_smi = fixed_array->get(i);
6721 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006723 }
6724 pos = Smi::cast(next_smi)->value();
6725 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006729 ASSERT(pos >= 0);
6730 ASSERT(len >= 0);
6731 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006732 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006733 }
6734 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 } else if (elt->IsString()) {
6736 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006737 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006738 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006739 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006745 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006747 return Failure::OutOfMemoryException();
6748 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006749 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 }
6751
6752 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 { MaybeObject* maybe_object =
6757 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006758 if (!maybe_object->ToObject(&object)) return maybe_object;
6759 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006760 SeqAsciiString* answer = SeqAsciiString::cast(object);
6761 StringBuilderConcatHelper(special,
6762 answer->GetChars(),
6763 fixed_array,
6764 array_length);
6765 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006767 { MaybeObject* maybe_object =
6768 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006769 if (!maybe_object->ToObject(&object)) return maybe_object;
6770 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006771 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6772 StringBuilderConcatHelper(special,
6773 answer->GetChars(),
6774 fixed_array,
6775 array_length);
6776 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778}
6779
6780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006781RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006782 NoHandleAllocation ha;
6783 ASSERT(args.length() == 3);
6784 CONVERT_CHECKED(JSArray, array, args[0]);
6785 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006787 return Failure::OutOfMemoryException();
6788 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006789 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006790 CONVERT_CHECKED(String, separator, args[2]);
6791
6792 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006794 }
6795 FixedArray* fixed_array = FixedArray::cast(array->elements());
6796 if (fixed_array->length() < array_length) {
6797 array_length = fixed_array->length();
6798 }
6799
6800 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 } else if (array_length == 1) {
6803 Object* first = fixed_array->get(0);
6804 if (first->IsString()) return first;
6805 }
6806
6807 int separator_length = separator->length();
6808 int max_nof_separators =
6809 (String::kMaxLength + separator_length - 1) / separator_length;
6810 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006812 return Failure::OutOfMemoryException();
6813 }
6814 int length = (array_length - 1) * separator_length;
6815 for (int i = 0; i < array_length; i++) {
6816 Object* element_obj = fixed_array->get(i);
6817 if (!element_obj->IsString()) {
6818 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006820 }
6821 String* element = String::cast(element_obj);
6822 int increment = element->length();
6823 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006825 return Failure::OutOfMemoryException();
6826 }
6827 length += increment;
6828 }
6829
6830 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 { MaybeObject* maybe_object =
6832 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006833 if (!maybe_object->ToObject(&object)) return maybe_object;
6834 }
6835 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6836
6837 uc16* sink = answer->GetChars();
6838#ifdef DEBUG
6839 uc16* end = sink + length;
6840#endif
6841
6842 String* first = String::cast(fixed_array->get(0));
6843 int first_length = first->length();
6844 String::WriteToFlat(first, sink, 0, first_length);
6845 sink += first_length;
6846
6847 for (int i = 1; i < array_length; i++) {
6848 ASSERT(sink + separator_length <= end);
6849 String::WriteToFlat(separator, sink, 0, separator_length);
6850 sink += separator_length;
6851
6852 String* element = String::cast(fixed_array->get(i));
6853 int element_length = element->length();
6854 ASSERT(sink + element_length <= end);
6855 String::WriteToFlat(element, sink, 0, element_length);
6856 sink += element_length;
6857 }
6858 ASSERT(sink == end);
6859
6860 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6861 return answer;
6862}
6863
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006864template <typename Char>
6865static void JoinSparseArrayWithSeparator(FixedArray* elements,
6866 int elements_length,
6867 uint32_t array_length,
6868 String* separator,
6869 Vector<Char> buffer) {
6870 int previous_separator_position = 0;
6871 int separator_length = separator->length();
6872 int cursor = 0;
6873 for (int i = 0; i < elements_length; i += 2) {
6874 int position = NumberToInt32(elements->get(i));
6875 String* string = String::cast(elements->get(i + 1));
6876 int string_length = string->length();
6877 if (string->length() > 0) {
6878 while (previous_separator_position < position) {
6879 String::WriteToFlat<Char>(separator, &buffer[cursor],
6880 0, separator_length);
6881 cursor += separator_length;
6882 previous_separator_position++;
6883 }
6884 String::WriteToFlat<Char>(string, &buffer[cursor],
6885 0, string_length);
6886 cursor += string->length();
6887 }
6888 }
6889 if (separator_length > 0) {
6890 // Array length must be representable as a signed 32-bit number,
6891 // otherwise the total string length would have been too large.
6892 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6893 int last_array_index = static_cast<int>(array_length - 1);
6894 while (previous_separator_position < last_array_index) {
6895 String::WriteToFlat<Char>(separator, &buffer[cursor],
6896 0, separator_length);
6897 cursor += separator_length;
6898 previous_separator_position++;
6899 }
6900 }
6901 ASSERT(cursor <= buffer.length());
6902}
6903
6904
6905RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6906 NoHandleAllocation ha;
6907 ASSERT(args.length() == 3);
6908 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006909 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6910 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006911 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6912 CONVERT_CHECKED(String, separator, args[2]);
6913 // elements_array is fast-mode JSarray of alternating positions
6914 // (increasing order) and strings.
6915 // array_length is length of original array (used to add separators);
6916 // separator is string to put between elements. Assumed to be non-empty.
6917
6918 // Find total length of join result.
6919 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006920 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006921 int max_string_length;
6922 if (is_ascii) {
6923 max_string_length = SeqAsciiString::kMaxLength;
6924 } else {
6925 max_string_length = SeqTwoByteString::kMaxLength;
6926 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006927 bool overflow = false;
6928 CONVERT_NUMBER_CHECKED(int, elements_length,
6929 Int32, elements_array->length());
6930 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6931 FixedArray* elements = FixedArray::cast(elements_array->elements());
6932 for (int i = 0; i < elements_length; i += 2) {
6933 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6934 CONVERT_CHECKED(String, string, elements->get(i + 1));
6935 int length = string->length();
6936 if (is_ascii && !string->IsAsciiRepresentation()) {
6937 is_ascii = false;
6938 max_string_length = SeqTwoByteString::kMaxLength;
6939 }
6940 if (length > max_string_length ||
6941 max_string_length - length < string_length) {
6942 overflow = true;
6943 break;
6944 }
6945 string_length += length;
6946 }
6947 int separator_length = separator->length();
6948 if (!overflow && separator_length > 0) {
6949 if (array_length <= 0x7fffffffu) {
6950 int separator_count = static_cast<int>(array_length) - 1;
6951 int remaining_length = max_string_length - string_length;
6952 if ((remaining_length / separator_length) >= separator_count) {
6953 string_length += separator_length * (array_length - 1);
6954 } else {
6955 // Not room for the separators within the maximal string length.
6956 overflow = true;
6957 }
6958 } else {
6959 // Nonempty separator and at least 2^31-1 separators necessary
6960 // means that the string is too large to create.
6961 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6962 overflow = true;
6963 }
6964 }
6965 if (overflow) {
6966 // Throw OutOfMemory exception for creating too large a string.
6967 V8::FatalProcessOutOfMemory("Array join result too large.");
6968 }
6969
6970 if (is_ascii) {
6971 MaybeObject* result_allocation =
6972 isolate->heap()->AllocateRawAsciiString(string_length);
6973 if (result_allocation->IsFailure()) return result_allocation;
6974 SeqAsciiString* result_string =
6975 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6976 JoinSparseArrayWithSeparator<char>(elements,
6977 elements_length,
6978 array_length,
6979 separator,
6980 Vector<char>(result_string->GetChars(),
6981 string_length));
6982 return result_string;
6983 } else {
6984 MaybeObject* result_allocation =
6985 isolate->heap()->AllocateRawTwoByteString(string_length);
6986 if (result_allocation->IsFailure()) return result_allocation;
6987 SeqTwoByteString* result_string =
6988 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6989 JoinSparseArrayWithSeparator<uc16>(elements,
6990 elements_length,
6991 array_length,
6992 separator,
6993 Vector<uc16>(result_string->GetChars(),
6994 string_length));
6995 return result_string;
6996 }
6997}
6998
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 2);
7003
7004 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7005 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007006 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007}
7008
7009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007010RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 NoHandleAllocation ha;
7012 ASSERT(args.length() == 2);
7013
7014 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7015 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017}
7018
7019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021 NoHandleAllocation ha;
7022 ASSERT(args.length() == 2);
7023
7024 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7025 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007026 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027}
7028
7029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007030RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 NoHandleAllocation ha;
7032 ASSERT(args.length() == 1);
7033
7034 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007035 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036}
7037
7038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007039RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040 NoHandleAllocation ha;
7041 ASSERT(args.length() == 2);
7042
7043 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7044 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007045 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007046}
7047
7048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007049RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 NoHandleAllocation ha;
7051 ASSERT(args.length() == 2);
7052
7053 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7054 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056}
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060 NoHandleAllocation ha;
7061 ASSERT(args.length() == 2);
7062
7063 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7064 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007065 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066}
7067
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070 NoHandleAllocation ha;
7071 ASSERT(args.length() == 2);
7072
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007073 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7074 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7076 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7077 if (x == y) return Smi::FromInt(EQUAL);
7078 Object* result;
7079 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7080 result = Smi::FromInt(EQUAL);
7081 } else {
7082 result = Smi::FromInt(NOT_EQUAL);
7083 }
7084 return result;
7085}
7086
7087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007088RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089 NoHandleAllocation ha;
7090 ASSERT(args.length() == 2);
7091
7092 CONVERT_CHECKED(String, x, args[0]);
7093 CONVERT_CHECKED(String, y, args[1]);
7094
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007095 bool not_equal = !x->Equals(y);
7096 // This is slightly convoluted because the value that signifies
7097 // equality is 0 and inequality is 1 so we have to negate the result
7098 // from String::Equals.
7099 ASSERT(not_equal == 0 || not_equal == 1);
7100 STATIC_CHECK(EQUAL == 0);
7101 STATIC_CHECK(NOT_EQUAL == 1);
7102 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 3);
7109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007110 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7111 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112 if (isnan(x) || isnan(y)) return args[2];
7113 if (x == y) return Smi::FromInt(EQUAL);
7114 if (isless(x, y)) return Smi::FromInt(LESS);
7115 return Smi::FromInt(GREATER);
7116}
7117
7118
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007119// Compare two Smis as if they were converted to strings and then
7120// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007122 NoHandleAllocation ha;
7123 ASSERT(args.length() == 2);
7124
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007125 // Extract the integer values from the Smis.
7126 CONVERT_CHECKED(Smi, x, args[0]);
7127 CONVERT_CHECKED(Smi, y, args[1]);
7128 int x_value = x->value();
7129 int y_value = y->value();
7130
7131 // If the integers are equal so are the string representations.
7132 if (x_value == y_value) return Smi::FromInt(EQUAL);
7133
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007134 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007135 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007136 if (x_value == 0 || y_value == 0)
7137 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007138
ager@chromium.org32912102009-01-16 10:38:43 +00007139 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140 // smallest because the char code of '-' is less than the char code
7141 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007142
7143 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7144 // architectures using 32-bit Smis.
7145 uint32_t x_scaled = x_value;
7146 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147 if (x_value < 0 || y_value < 0) {
7148 if (y_value >= 0) return Smi::FromInt(LESS);
7149 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007150 x_scaled = -x_value;
7151 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152 }
7153
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007154 static const uint32_t kPowersOf10[] = {
7155 1, 10, 100, 1000, 10*1000, 100*1000,
7156 1000*1000, 10*1000*1000, 100*1000*1000,
7157 1000*1000*1000
7158 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007159
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007160 // If the integers have the same number of decimal digits they can be
7161 // compared directly as the numeric order is the same as the
7162 // lexicographic order. If one integer has fewer digits, it is scaled
7163 // by some power of 10 to have the same number of digits as the longer
7164 // integer. If the scaled integers are equal it means the shorter
7165 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007166
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007167 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7168 int x_log2 = IntegerLog2(x_scaled);
7169 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7170 x_log10 -= x_scaled < kPowersOf10[x_log10];
7171
7172 int y_log2 = IntegerLog2(y_scaled);
7173 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7174 y_log10 -= y_scaled < kPowersOf10[y_log10];
7175
7176 int tie = EQUAL;
7177
7178 if (x_log10 < y_log10) {
7179 // X has fewer digits. We would like to simply scale up X but that
7180 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7181 // be scaled up to 9_000_000_000. So we scale up by the next
7182 // smallest power and scale down Y to drop one digit. It is OK to
7183 // drop one digit from the longer integer since the final digit is
7184 // past the length of the shorter integer.
7185 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7186 y_scaled /= 10;
7187 tie = LESS;
7188 } else if (y_log10 < x_log10) {
7189 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7190 x_scaled /= 10;
7191 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 }
7193
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7195 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7196 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007197}
7198
7199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200static Object* StringInputBufferCompare(RuntimeState* state,
7201 String* x,
7202 String* y) {
7203 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7204 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007205 bufx.Reset(x);
7206 bufy.Reset(y);
7207 while (bufx.has_more() && bufy.has_more()) {
7208 int d = bufx.GetNext() - bufy.GetNext();
7209 if (d < 0) return Smi::FromInt(LESS);
7210 else if (d > 0) return Smi::FromInt(GREATER);
7211 }
7212
7213 // x is (non-trivial) prefix of y:
7214 if (bufy.has_more()) return Smi::FromInt(LESS);
7215 // y is prefix of x:
7216 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7217}
7218
7219
7220static Object* FlatStringCompare(String* x, String* y) {
7221 ASSERT(x->IsFlat());
7222 ASSERT(y->IsFlat());
7223 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7224 int prefix_length = x->length();
7225 if (y->length() < prefix_length) {
7226 prefix_length = y->length();
7227 equal_prefix_result = Smi::FromInt(GREATER);
7228 } else if (y->length() > prefix_length) {
7229 equal_prefix_result = Smi::FromInt(LESS);
7230 }
7231 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007232 String::FlatContent x_content = x->GetFlatContent();
7233 String::FlatContent y_content = y->GetFlatContent();
7234 if (x_content.IsAscii()) {
7235 Vector<const char> x_chars = x_content.ToAsciiVector();
7236 if (y_content.IsAscii()) {
7237 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007238 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007239 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007240 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007241 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7242 }
7243 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007244 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7245 if (y_content.IsAscii()) {
7246 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007247 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7248 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007249 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007250 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7251 }
7252 }
7253 Object* result;
7254 if (r == 0) {
7255 result = equal_prefix_result;
7256 } else {
7257 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7258 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 ASSERT(result ==
7260 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007261 return result;
7262}
7263
7264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007265RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 NoHandleAllocation ha;
7267 ASSERT(args.length() == 2);
7268
7269 CONVERT_CHECKED(String, x, args[0]);
7270 CONVERT_CHECKED(String, y, args[1]);
7271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007272 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 // A few fast case tests before we flatten.
7275 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007276 if (y->length() == 0) {
7277 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007279 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280 return Smi::FromInt(LESS);
7281 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007282
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007283 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007284 if (d < 0) return Smi::FromInt(LESS);
7285 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286
lrn@chromium.org303ada72010-10-27 09:33:13 +00007287 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007289 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007291 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007295 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297}
7298
7299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007300RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 NoHandleAllocation ha;
7302 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007305 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307}
7308
7309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007310RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317}
7318
7319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327}
7328
7329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330static const double kPiDividedBy4 = 0.78539816339744830962;
7331
7332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 NoHandleAllocation ha;
7335 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007338 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7339 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340 double result;
7341 if (isinf(x) && isinf(y)) {
7342 // Make sure that the result in case of two infinite arguments
7343 // is a multiple of Pi / 4. The sign of the result is determined
7344 // by the first argument (x) and the sign of the second argument
7345 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 int multiplier = (x < 0) ? -1 : 1;
7347 if (y < 0) multiplier *= 3;
7348 result = multiplier * kPiDividedBy4;
7349 } else {
7350 result = atan2(x, y);
7351 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353}
7354
7355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007356RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357 NoHandleAllocation ha;
7358 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007361 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363}
7364
7365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007366RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373}
7374
7375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
7384
7385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007405// Slow version of Math.pow. We check for fast paths for special cases.
7406// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007407RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 NoHandleAllocation ha;
7409 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007412 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007413
7414 // If the second argument is a smi, it is much faster to call the
7415 // custom powi() function than the generic pow().
7416 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007417 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007419 }
7420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007421 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007422 int y_int = static_cast<int>(y);
7423 double result;
7424 if (y == y_int) {
7425 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7426 } else if (y == 0.5) {
7427 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7428 } else if (y == -0.5) {
7429 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7430 } else {
7431 result = power_double_double(x, y);
7432 }
7433 if (isnan(result)) return isolate->heap()->nan_value();
7434 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435}
7436
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007437// Fast version of Math.pow if we know that y is not an integer and y is not
7438// -0.5 or 0.5. Used as slow case from fullcodegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007439RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007440 NoHandleAllocation ha;
7441 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007442 isolate->counters()->math_pow()->Increment();
7443
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007444 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7445 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007446 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007447 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007448 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449 double result = power_double_double(x, y);
7450 if (isnan(result)) return isolate->heap()->nan_value();
7451 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007452 }
7453}
7454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
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_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007461 if (!args[0]->IsHeapNumber()) {
7462 // Must be smi. Return the argument unchanged for all the other types
7463 // to make fuzz-natives test happy.
7464 return args[0];
7465 }
7466
7467 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7468
7469 double value = number->value();
7470 int exponent = number->get_exponent();
7471 int sign = number->get_sign();
7472
danno@chromium.org160a7b02011-04-18 15:51:38 +00007473 if (exponent < -1) {
7474 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7475 if (sign) return isolate->heap()->minus_zero_value();
7476 return Smi::FromInt(0);
7477 }
7478
7479 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7480 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7481 // agument holds for 32-bit smis).
7482 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007483 return Smi::FromInt(static_cast<int>(value + 0.5));
7484 }
7485
7486 // If the magnitude is big enough, there's no place for fraction part. If we
7487 // try to add 0.5 to this number, 1.0 will be added instead.
7488 if (exponent >= 52) {
7489 return number;
7490 }
7491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007493
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007494 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007495 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007496}
7497
7498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007499RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500 NoHandleAllocation ha;
7501 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007502 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007504 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007505 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007506}
7507
7508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510 NoHandleAllocation ha;
7511 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007514 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007515 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516}
7517
7518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007519RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 NoHandleAllocation ha;
7521 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007522 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007524 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007525 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526}
7527
7528
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007529static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007530 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7531 181, 212, 243, 273, 304, 334};
7532 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7533 182, 213, 244, 274, 305, 335};
7534
7535 year += month / 12;
7536 month %= 12;
7537 if (month < 0) {
7538 year--;
7539 month += 12;
7540 }
7541
7542 ASSERT(month >= 0);
7543 ASSERT(month < 12);
7544
7545 // year_delta is an arbitrary number such that:
7546 // a) year_delta = -1 (mod 400)
7547 // b) year + year_delta > 0 for years in the range defined by
7548 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7549 // Jan 1 1970. This is required so that we don't run into integer
7550 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007552 // operations.
7553 static const int year_delta = 399999;
7554 static const int base_day = 365 * (1970 + year_delta) +
7555 (1970 + year_delta) / 4 -
7556 (1970 + year_delta) / 100 +
7557 (1970 + year_delta) / 400;
7558
7559 int year1 = year + year_delta;
7560 int day_from_year = 365 * year1 +
7561 year1 / 4 -
7562 year1 / 100 +
7563 year1 / 400 -
7564 base_day;
7565
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007566 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7567 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007568 }
7569
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007570 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007571}
7572
7573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007574RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007575 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007576 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007577
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007578 CONVERT_SMI_ARG_CHECKED(year, 0);
7579 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007581 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007582}
7583
7584
7585static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7586static const int kDaysIn4Years = 4 * 365 + 1;
7587static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7588static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7589static const int kDays1970to2000 = 30 * 365 + 7;
7590static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7591 kDays1970to2000;
7592static const int kYearsOffset = 400000;
7593
7594static const char kDayInYear[] = {
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30,
7613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7614 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7616 22, 23, 24, 25, 26, 27, 28, 29, 30,
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7619
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7644
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30,
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
7669
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7686 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7687 22, 23, 24, 25, 26, 27, 28, 29, 30,
7688 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7689 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31};
7694
7695static const char kMonthInYear[] = {
7696 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,
7697 0, 0, 0, 0, 0, 0,
7698 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,
7699 1, 1, 1,
7700 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,
7701 2, 2, 2, 2, 2, 2,
7702 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,
7703 3, 3, 3, 3, 3,
7704 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,
7705 4, 4, 4, 4, 4, 4,
7706 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,
7707 5, 5, 5, 5, 5,
7708 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,
7709 6, 6, 6, 6, 6, 6,
7710 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,
7711 7, 7, 7, 7, 7, 7,
7712 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,
7713 8, 8, 8, 8, 8,
7714 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,
7715 9, 9, 9, 9, 9, 9,
7716 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7717 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7718 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7719 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7720
7721 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,
7722 0, 0, 0, 0, 0, 0,
7723 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,
7724 1, 1, 1,
7725 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,
7726 2, 2, 2, 2, 2, 2,
7727 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,
7728 3, 3, 3, 3, 3,
7729 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,
7730 4, 4, 4, 4, 4, 4,
7731 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,
7732 5, 5, 5, 5, 5,
7733 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,
7734 6, 6, 6, 6, 6, 6,
7735 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,
7736 7, 7, 7, 7, 7, 7,
7737 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,
7738 8, 8, 8, 8, 8,
7739 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,
7740 9, 9, 9, 9, 9, 9,
7741 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7742 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7743 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7744 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7745
7746 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,
7747 0, 0, 0, 0, 0, 0,
7748 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,
7749 1, 1, 1, 1,
7750 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,
7751 2, 2, 2, 2, 2, 2,
7752 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,
7753 3, 3, 3, 3, 3,
7754 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,
7755 4, 4, 4, 4, 4, 4,
7756 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,
7757 5, 5, 5, 5, 5,
7758 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,
7759 6, 6, 6, 6, 6, 6,
7760 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,
7761 7, 7, 7, 7, 7, 7,
7762 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,
7763 8, 8, 8, 8, 8,
7764 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,
7765 9, 9, 9, 9, 9, 9,
7766 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7767 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7768 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7769 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7770
7771 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,
7772 0, 0, 0, 0, 0, 0,
7773 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,
7774 1, 1, 1,
7775 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,
7776 2, 2, 2, 2, 2, 2,
7777 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,
7778 3, 3, 3, 3, 3,
7779 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,
7780 4, 4, 4, 4, 4, 4,
7781 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,
7782 5, 5, 5, 5, 5,
7783 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,
7784 6, 6, 6, 6, 6, 6,
7785 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,
7786 7, 7, 7, 7, 7, 7,
7787 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,
7788 8, 8, 8, 8, 8,
7789 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,
7790 9, 9, 9, 9, 9, 9,
7791 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7792 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7793 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7794 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7795
7796
7797// This function works for dates from 1970 to 2099.
7798static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007799 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007800#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007801 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007802#endif
7803
7804 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7805 date %= kDaysIn4Years;
7806
7807 month = kMonthInYear[date];
7808 day = kDayInYear[date];
7809
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007810 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007811}
7812
7813
7814static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007815 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007816#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007817 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007818#endif
7819
7820 date += kDaysOffset;
7821 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7822 date %= kDaysIn400Years;
7823
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007824 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007825
7826 date--;
7827 int yd1 = date / kDaysIn100Years;
7828 date %= kDaysIn100Years;
7829 year += 100 * yd1;
7830
7831 date++;
7832 int yd2 = date / kDaysIn4Years;
7833 date %= kDaysIn4Years;
7834 year += 4 * yd2;
7835
7836 date--;
7837 int yd3 = date / 365;
7838 date %= 365;
7839 year += yd3;
7840
7841 bool is_leap = (!yd1 || yd2) && !yd3;
7842
7843 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007844 ASSERT(is_leap || (date >= 0));
7845 ASSERT((date < 365) || (is_leap && (date < 366)));
7846 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007847 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7848 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007849
7850 if (is_leap) {
7851 day = kDayInYear[2*365 + 1 + date];
7852 month = kMonthInYear[2*365 + 1 + date];
7853 } else {
7854 day = kDayInYear[date];
7855 month = kMonthInYear[date];
7856 }
7857
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007858 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007859}
7860
7861
7862static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007863 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007864 if (date >= 0 && date < 32 * kDaysIn4Years) {
7865 DateYMDFromTimeAfter1970(date, year, month, day);
7866 } else {
7867 DateYMDFromTimeSlow(date, year, month, day);
7868 }
7869}
7870
7871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007872RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007873 NoHandleAllocation ha;
7874 ASSERT(args.length() == 2);
7875
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007876 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007877 CONVERT_CHECKED(JSArray, res_array, args[1]);
7878
7879 int year, month, day;
7880 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7881
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007882 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7883 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007884 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007885
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007886 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7887 if (maybe->IsFailure()) return maybe;
7888 FixedArray* elms = FixedArray::cast(res_array->elements());
7889 elms->set(0, Smi::FromInt(year));
7890 elms->set(1, Smi::FromInt(month));
7891 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007898 HandleScope scope(isolate);
7899 ASSERT(args.length() == 3);
7900
7901 Handle<JSFunction> callee = args.at<JSFunction>(0);
7902 Object** parameters = reinterpret_cast<Object**>(args[1]);
7903 const int argument_count = Smi::cast(args[2])->value();
7904
7905 Handle<JSObject> result =
7906 isolate->factory()->NewArgumentsObject(callee, argument_count);
7907 // Allocate the elements if needed.
7908 int parameter_count = callee->shared()->formal_parameter_count();
7909 if (argument_count > 0) {
7910 if (parameter_count > 0) {
7911 int mapped_count = Min(argument_count, parameter_count);
7912 Handle<FixedArray> parameter_map =
7913 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7914 parameter_map->set_map(
7915 isolate->heap()->non_strict_arguments_elements_map());
7916
7917 Handle<Map> old_map(result->map());
7918 Handle<Map> new_map =
7919 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007920 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007921
7922 result->set_map(*new_map);
7923 result->set_elements(*parameter_map);
7924
7925 // Store the context and the arguments array at the beginning of the
7926 // parameter map.
7927 Handle<Context> context(isolate->context());
7928 Handle<FixedArray> arguments =
7929 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7930 parameter_map->set(0, *context);
7931 parameter_map->set(1, *arguments);
7932
7933 // Loop over the actual parameters backwards.
7934 int index = argument_count - 1;
7935 while (index >= mapped_count) {
7936 // These go directly in the arguments array and have no
7937 // corresponding slot in the parameter map.
7938 arguments->set(index, *(parameters - index - 1));
7939 --index;
7940 }
7941
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007942 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007943 while (index >= 0) {
7944 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007945 Handle<String> name(scope_info->ParameterName(index));
7946 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007947 bool duplicate = false;
7948 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007949 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007950 duplicate = true;
7951 break;
7952 }
7953 }
7954
7955 if (duplicate) {
7956 // This goes directly in the arguments array with a hole in the
7957 // parameter map.
7958 arguments->set(index, *(parameters - index - 1));
7959 parameter_map->set_the_hole(index + 2);
7960 } else {
7961 // The context index goes in the parameter map with a hole in the
7962 // arguments array.
7963 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007964 for (int j = 0; j < context_local_count; ++j) {
7965 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 context_index = j;
7967 break;
7968 }
7969 }
7970 ASSERT(context_index >= 0);
7971 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007972 parameter_map->set(index + 2, Smi::FromInt(
7973 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007974 }
7975
7976 --index;
7977 }
7978 } else {
7979 // If there is no aliasing, the arguments object elements are not
7980 // special in any way.
7981 Handle<FixedArray> elements =
7982 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7983 result->set_elements(*elements);
7984 for (int i = 0; i < argument_count; ++i) {
7985 elements->set(i, *(parameters - i - 1));
7986 }
7987 }
7988 }
7989 return *result;
7990}
7991
7992
7993RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007994 NoHandleAllocation ha;
7995 ASSERT(args.length() == 3);
7996
7997 JSFunction* callee = JSFunction::cast(args[0]);
7998 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007999 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008000
lrn@chromium.org303ada72010-10-27 09:33:13 +00008001 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008002 { MaybeObject* maybe_result =
8003 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008004 if (!maybe_result->ToObject(&result)) return maybe_result;
8005 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008006 // Allocate the elements if needed.
8007 if (length > 0) {
8008 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008009 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008011 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8012 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008013
8014 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008015 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008016 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008017 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008018
8019 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008020 for (int i = 0; i < length; i++) {
8021 array->set(i, *--parameters, mode);
8022 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008023 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008024 }
8025 return result;
8026}
8027
8028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008029RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008031 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008032 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008033 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008034 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008037 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008038 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8041 context,
8042 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 return *result;
8044}
8045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008046
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008047// Find the arguments of the JavaScript function invocation that called
8048// into C++ code. Collect these in a newly allocated array of handles (possibly
8049// prefixed by a number of empty handles).
8050static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8051 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008052 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008053 // Find frame containing arguments passed to the caller.
8054 JavaScriptFrameIterator it;
8055 JavaScriptFrame* frame = it.frame();
8056 List<JSFunction*> functions(2);
8057 frame->GetFunctions(&functions);
8058 if (functions.length() > 1) {
8059 int inlined_frame_index = functions.length() - 1;
8060 JSFunction* inlined_function = functions[inlined_frame_index];
8061 int args_count = inlined_function->shared()->formal_parameter_count();
8062 ScopedVector<SlotRef> args_slots(args_count);
8063 SlotRef::ComputeSlotMappingForArguments(frame,
8064 inlined_frame_index,
8065 &args_slots);
8066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008067 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008068 SmartArrayPointer<Handle<Object> > param_data(
8069 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070 for (int i = 0; i < args_count; i++) {
8071 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008072 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073 }
8074 return param_data;
8075 } else {
8076 it.AdvanceToArgumentsFrame();
8077 frame = it.frame();
8078 int args_count = frame->ComputeParametersCount();
8079
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008080 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008081 SmartArrayPointer<Handle<Object> > param_data(
8082 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083 for (int i = 0; i < args_count; i++) {
8084 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008085 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086 }
8087 return param_data;
8088 }
8089}
8090
8091
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008092RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8093 HandleScope scope(isolate);
8094 ASSERT(args.length() == 4);
8095 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8096 RUNTIME_ASSERT(args[3]->IsNumber());
8097 Handle<Object> bindee = args.at<Object>(1);
8098
8099 // TODO(lrn): Create bound function in C++ code from premade shared info.
8100 bound_function->shared()->set_bound(true);
8101 // Get all arguments of calling function (Function.prototype.bind).
8102 int argc = 0;
8103 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8104 // Don't count the this-arg.
8105 if (argc > 0) {
8106 ASSERT(*arguments[0] == args[2]);
8107 argc--;
8108 } else {
8109 ASSERT(args[2]->IsUndefined());
8110 }
8111 // Initialize array of bindings (function, this, and any existing arguments
8112 // if the function was already bound).
8113 Handle<FixedArray> new_bindings;
8114 int i;
8115 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8116 Handle<FixedArray> old_bindings(
8117 JSFunction::cast(*bindee)->function_bindings());
8118 new_bindings =
8119 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8120 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8121 i = 0;
8122 for (int n = old_bindings->length(); i < n; i++) {
8123 new_bindings->set(i, old_bindings->get(i));
8124 }
8125 } else {
8126 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8127 new_bindings = isolate->factory()->NewFixedArray(array_size);
8128 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8129 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8130 i = 2;
8131 }
8132 // Copy arguments, skipping the first which is "this_arg".
8133 for (int j = 0; j < argc; j++, i++) {
8134 new_bindings->set(i, *arguments[j + 1]);
8135 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008136 new_bindings->set_map_no_write_barrier(
8137 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008138 bound_function->set_function_bindings(*new_bindings);
8139
8140 // Update length.
8141 Handle<String> length_symbol = isolate->factory()->length_symbol();
8142 Handle<Object> new_length(args.at<Object>(3));
8143 PropertyAttributes attr =
8144 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8145 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8146 return *bound_function;
8147}
8148
8149
8150RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8151 HandleScope handles(isolate);
8152 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008153 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008154 if (callable->IsJSFunction()) {
8155 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8156 if (function->shared()->bound()) {
8157 Handle<FixedArray> bindings(function->function_bindings());
8158 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8159 return *isolate->factory()->NewJSArrayWithElements(bindings);
8160 }
8161 }
8162 return isolate->heap()->undefined_value();
8163}
8164
8165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008166RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008167 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008168 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008169 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008170 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008171 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008172
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008173 // The argument is a bound function. Extract its bound arguments
8174 // and callable.
8175 Handle<FixedArray> bound_args =
8176 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8177 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8178 Handle<Object> bound_function(
8179 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8180 ASSERT(!bound_function->IsJSFunction() ||
8181 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008183 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008184 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008185 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008186 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008187 param_data[i] = Handle<Object>(bound_args->get(
8188 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008189 }
8190
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008191 if (!bound_function->IsJSFunction()) {
8192 bool exception_thrown;
8193 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8194 &exception_thrown);
8195 if (exception_thrown) return Failure::Exception();
8196 }
8197 ASSERT(bound_function->IsJSFunction());
8198
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008199 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008200 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008201 Execution::New(Handle<JSFunction>::cast(bound_function),
8202 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008203 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008205 }
8206 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008207 return *result;
8208}
8209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008211static void TrySettingInlineConstructStub(Isolate* isolate,
8212 Handle<JSFunction> function) {
8213 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008214 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008216 }
8217 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008218 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008219 Handle<Code> code = compiler.CompileConstructStub(function);
8220 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008221 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008222}
8223
8224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008225RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008226 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227 ASSERT(args.length() == 1);
8228
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008229 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008231 // If the constructor isn't a proper function we throw a type error.
8232 if (!constructor->IsJSFunction()) {
8233 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8234 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008235 isolate->factory()->NewTypeError("not_constructor", arguments);
8236 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008237 }
8238
8239 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008240
8241 // If function should not have prototype, construction is not allowed. In this
8242 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008243 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008244 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8245 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 isolate->factory()->NewTypeError("not_constructor", arguments);
8247 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008248 }
8249
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008250#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 if (debug->StepInActive()) {
8254 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008255 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008256#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258 if (function->has_initial_map()) {
8259 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 // The 'Function' function ignores the receiver object when
8261 // called using 'new' and creates a new JSFunction object that
8262 // is returned. The receiver object is only used for error
8263 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008264 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008265 // allocate JSFunctions since it does not properly initialize
8266 // the shared part of the function. Since the receiver is
8267 // ignored anyway, we use the global object as the receiver
8268 // instead of a new JSFunction object. This way, errors are
8269 // reported the same way whether or not 'Function' is called
8270 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 }
8274
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008275 // The function should be compiled for the optimization hints to be
8276 // available. We cannot use EnsureCompiled because that forces a
8277 // compilation through the shared function info which makes it
8278 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008279 if (!function->is_compiled()) {
8280 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8281 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008282
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008283 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008284 if (!function->has_initial_map() &&
8285 shared->IsInobjectSlackTrackingInProgress()) {
8286 // The tracking is already in progress for another function. We can only
8287 // track one initial_map at a time, so we force the completion before the
8288 // function is called as a constructor for the first time.
8289 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008290 }
8291
8292 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8294 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008295 // Delay setting the stub if inobject slack tracking is in progress.
8296 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008298 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008300 isolate->counters()->constructed_objects()->Increment();
8301 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008302
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008303 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304}
8305
8306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008307RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008309 ASSERT(args.length() == 1);
8310
8311 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8312 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008316}
8317
8318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 ASSERT(args.length() == 1);
8322
8323 Handle<JSFunction> function = args.at<JSFunction>(0);
8324#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008325 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008327 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 PrintF("]\n");
8329 }
8330#endif
8331
lrn@chromium.org34e60782011-09-15 07:25:40 +00008332 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008334 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 return Failure::Exception();
8336 }
8337
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008338 // All done. Return the compiled code.
8339 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340 return function->code();
8341}
8342
8343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008344RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008346 ASSERT(args.length() == 1);
8347 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008348
8349 // If the function is not compiled ignore the lazy
8350 // recompilation. This can happen if the debugger is activated and
8351 // the function is returned to the not compiled state.
8352 if (!function->shared()->is_compiled()) {
8353 function->ReplaceCode(function->shared()->code());
8354 return function->code();
8355 }
8356
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357 // If the function is not optimizable or debugger is active continue using the
8358 // code from the full compiler.
8359 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008360 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008361 if (FLAG_trace_opt) {
8362 PrintF("[failed to optimize ");
8363 function->PrintName();
8364 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8365 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008366 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008367 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008368 function->ReplaceCode(function->shared()->code());
8369 return function->code();
8370 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008371 if (JSFunction::CompileOptimized(function,
8372 AstNode::kNoNumber,
8373 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008374 return function->code();
8375 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008376 if (FLAG_trace_opt) {
8377 PrintF("[failed to optimize ");
8378 function->PrintName();
8379 PrintF(": optimized compilation failed]\n");
8380 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008381 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008382 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008383}
8384
8385
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008386class ActivationsFinder : public ThreadVisitor {
8387 public:
8388 explicit ActivationsFinder(JSFunction* function)
8389 : function_(function), has_activations_(false) {}
8390
8391 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8392 if (has_activations_) return;
8393
8394 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8395 JavaScriptFrame* frame = it.frame();
8396 if (frame->is_optimized() && frame->function() == function_) {
8397 has_activations_ = true;
8398 return;
8399 }
8400 }
8401 }
8402
8403 bool has_activations() { return has_activations_; }
8404
8405 private:
8406 JSFunction* function_;
8407 bool has_activations_;
8408};
8409
8410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008411RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008413 ASSERT(args.length() == 1);
8414 RUNTIME_ASSERT(args[0]->IsSmi());
8415 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008416 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8418 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419 int frames = deoptimizer->output_count();
8420
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008421 deoptimizer->MaterializeHeapNumbers();
8422 delete deoptimizer;
8423
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008424 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008426 for (int i = 0; i < frames - 1; i++) it.Advance();
8427 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008428
8429 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008430 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008431 Handle<Object> arguments;
8432 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 if (arguments.is_null()) {
8435 // FunctionGetArguments can't throw an exception, so cast away the
8436 // doubt with an assert.
8437 arguments = Handle<Object>(
8438 Accessors::FunctionGetArguments(*function,
8439 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 ASSERT(*arguments != isolate->heap()->null_value());
8441 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 }
8443 frame->SetExpression(i, *arguments);
8444 }
8445 }
8446
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 if (type == Deoptimizer::EAGER) {
8448 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 }
8450
8451 // Avoid doing too much work when running with --always-opt and keep
8452 // the optimized code around.
8453 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008454 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 }
8456
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008457 // Find other optimized activations of the function.
8458 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459 while (!it.done()) {
8460 JavaScriptFrame* frame = it.frame();
8461 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008462 has_other_activations = true;
8463 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008464 }
8465 it.Advance();
8466 }
8467
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008468 if (!has_other_activations) {
8469 ActivationsFinder activations_finder(*function);
8470 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8471 has_other_activations = activations_finder.has_activations();
8472 }
8473
8474 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008475 if (FLAG_trace_deopt) {
8476 PrintF("[removing optimized code for: ");
8477 function->PrintName();
8478 PrintF("]\n");
8479 }
8480 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008481 } else {
8482 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008492}
8493
8494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008495RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008497 ASSERT(args.length() == 1);
8498 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008499 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500
8501 Deoptimizer::DeoptimizeFunction(*function);
8502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008504}
8505
8506
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008507RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8508#if defined(USE_SIMULATOR)
8509 return isolate->heap()->true_value();
8510#else
8511 return isolate->heap()->false_value();
8512#endif
8513}
8514
8515
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008516RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8517 HandleScope scope(isolate);
8518 ASSERT(args.length() == 1);
8519 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8520 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8521 function->MarkForLazyRecompilation();
8522 return isolate->heap()->undefined_value();
8523}
8524
8525
lrn@chromium.org1c092762011-05-09 09:42:16 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8527 HandleScope scope(isolate);
8528 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008529 // The least significant bit (after untagging) indicates whether the
8530 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008531 if (!V8::UseCrankshaft()) {
8532 return Smi::FromInt(4); // 4 == "never".
8533 }
8534 if (FLAG_always_opt) {
8535 return Smi::FromInt(3); // 3 == "always".
8536 }
8537 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8538 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8539 : Smi::FromInt(2); // 2 == "no".
8540}
8541
8542
8543RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8544 HandleScope scope(isolate);
8545 ASSERT(args.length() == 1);
8546 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8547 return Smi::FromInt(function->shared()->opt_count());
8548}
8549
8550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008551RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008553 ASSERT(args.length() == 1);
8554 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8555
8556 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008557 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558
8559 // We have hit a back edge in an unoptimized frame for a function that was
8560 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008562 // Keep track of whether we've succeeded in optimizing.
8563 bool succeeded = unoptimized->optimizable();
8564 if (succeeded) {
8565 // If we are trying to do OSR when there are already optimized
8566 // activations of the function, it means (a) the function is directly or
8567 // indirectly recursive and (b) an optimized invocation has been
8568 // deoptimized so that we are currently in an unoptimized activation.
8569 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008570 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008571 while (succeeded && !it.done()) {
8572 JavaScriptFrame* frame = it.frame();
8573 succeeded = !frame->is_optimized() || frame->function() != *function;
8574 it.Advance();
8575 }
8576 }
8577
8578 int ast_id = AstNode::kNoNumber;
8579 if (succeeded) {
8580 // The top JS function is this one, the PC is somewhere in the
8581 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008582 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008583 JavaScriptFrame* frame = it.frame();
8584 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008585 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008586 ASSERT(unoptimized->contains(frame->pc()));
8587
8588 // Use linear search of the unoptimized code's stack check table to find
8589 // the AST id matching the PC.
8590 Address start = unoptimized->instruction_start();
8591 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008592 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593 uint32_t table_length = Memory::uint32_at(table_cursor);
8594 table_cursor += kIntSize;
8595 for (unsigned i = 0; i < table_length; ++i) {
8596 // Table entries are (AST id, pc offset) pairs.
8597 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8598 if (pc_offset == target_pc_offset) {
8599 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8600 break;
8601 }
8602 table_cursor += 2 * kIntSize;
8603 }
8604 ASSERT(ast_id != AstNode::kNoNumber);
8605 if (FLAG_trace_osr) {
8606 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8607 function->PrintName();
8608 PrintF("]\n");
8609 }
8610
8611 // Try to compile the optimized code. A true return value from
8612 // CompileOptimized means that compilation succeeded, not necessarily
8613 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008614 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008615 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008616 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8617 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008618 if (data->OsrPcOffset()->value() >= 0) {
8619 if (FLAG_trace_osr) {
8620 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008621 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008622 }
8623 ASSERT(data->OsrAstId()->value() == ast_id);
8624 } else {
8625 // We may never generate the desired OSR entry if we emit an
8626 // early deoptimize.
8627 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008629 } else {
8630 succeeded = false;
8631 }
8632 }
8633
8634 // Revert to the original stack checks in the original unoptimized code.
8635 if (FLAG_trace_osr) {
8636 PrintF("[restoring original stack checks in ");
8637 function->PrintName();
8638 PrintF("]\n");
8639 }
8640 StackCheckStub check_stub;
8641 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008642 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008643 Deoptimizer::RevertStackCheckCode(*unoptimized,
8644 *check_code,
8645 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646
8647 // Allow OSR only at nesting level zero again.
8648 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8649
8650 // If the optimization attempt succeeded, return the AST id tagged as a
8651 // smi. This tells the builtin that we need to translate the unoptimized
8652 // frame to an optimized one.
8653 if (succeeded) {
8654 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8655 return Smi::FromInt(ast_id);
8656 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008657 if (function->IsMarkedForLazyRecompilation()) {
8658 function->ReplaceCode(function->shared()->code());
8659 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008660 return Smi::FromInt(-1);
8661 }
8662}
8663
8664
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008665RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8666 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8667 return isolate->heap()->undefined_value();
8668}
8669
8670
danno@chromium.orgc612e022011-11-10 11:38:15 +00008671RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8672 HandleScope scope(isolate);
8673 ASSERT(args.length() >= 2);
8674 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8675 Object* receiver = args[0];
8676 int argc = args.length() - 2;
8677
8678 // If there are too many arguments, allocate argv via malloc.
8679 const int argv_small_size = 10;
8680 Handle<Object> argv_small_buffer[argv_small_size];
8681 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8682 Handle<Object>* argv = argv_small_buffer;
8683 if (argc > argv_small_size) {
8684 argv = new Handle<Object>[argc];
8685 if (argv == NULL) return isolate->StackOverflow();
8686 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8687 }
8688
8689 for (int i = 0; i < argc; ++i) {
8690 MaybeObject* maybe = args[1 + i];
8691 Object* object;
8692 if (!maybe->To<Object>(&object)) return maybe;
8693 argv[i] = Handle<Object>(object);
8694 }
8695
8696 bool threw;
8697 Handle<JSReceiver> hfun(fun);
8698 Handle<Object> hreceiver(receiver);
8699 Handle<Object> result =
8700 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8701
8702 if (threw) return Failure::Exception();
8703 return *result;
8704}
8705
8706
lrn@chromium.org34e60782011-09-15 07:25:40 +00008707RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8708 HandleScope scope(isolate);
8709 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008710 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8711 Handle<Object> receiver = args.at<Object>(1);
8712 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8713 CONVERT_SMI_ARG_CHECKED(offset, 3);
8714 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008715 ASSERT(offset >= 0);
8716 ASSERT(argc >= 0);
8717
8718 // If there are too many arguments, allocate argv via malloc.
8719 const int argv_small_size = 10;
8720 Handle<Object> argv_small_buffer[argv_small_size];
8721 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8722 Handle<Object>* argv = argv_small_buffer;
8723 if (argc > argv_small_size) {
8724 argv = new Handle<Object>[argc];
8725 if (argv == NULL) return isolate->StackOverflow();
8726 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8727 }
8728
8729 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008730 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008731 }
8732
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008733 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008734 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008735 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008736
8737 if (threw) return Failure::Exception();
8738 return *result;
8739}
8740
8741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008742RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008743 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744 ASSERT(args.length() == 1);
8745 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8746 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8747}
8748
8749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008751 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008752 ASSERT(args.length() == 1);
8753 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8754 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8755}
8756
8757
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008758RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008759 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008760 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008761
kasper.lund7276f142008-07-30 08:49:36 +00008762 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008763 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008764 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008765 { MaybeObject* maybe_result =
8766 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008767 if (!maybe_result->ToObject(&result)) return maybe_result;
8768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008770 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771
kasper.lund7276f142008-07-30 08:49:36 +00008772 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773}
8774
lrn@chromium.org303ada72010-10-27 09:33:13 +00008775
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008776RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8777 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008778 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008779 JSObject* extension_object;
8780 if (args[0]->IsJSObject()) {
8781 extension_object = JSObject::cast(args[0]);
8782 } else {
8783 // Convert the object to a proper JavaScript object.
8784 MaybeObject* maybe_js_object = args[0]->ToObject();
8785 if (!maybe_js_object->To(&extension_object)) {
8786 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8787 HandleScope scope(isolate);
8788 Handle<Object> handle = args.at<Object>(0);
8789 Handle<Object> result =
8790 isolate->factory()->NewTypeError("with_expression",
8791 HandleVector(&handle, 1));
8792 return isolate->Throw(*result);
8793 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008794 return maybe_js_object;
8795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796 }
8797 }
8798
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008799 JSFunction* function;
8800 if (args[1]->IsSmi()) {
8801 // A smi sentinel indicates a context nested inside global code rather
8802 // than some function. There is a canonical empty function that can be
8803 // gotten from the global context.
8804 function = isolate->context()->global_context()->closure();
8805 } else {
8806 function = JSFunction::cast(args[1]);
8807 }
8808
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008809 Context* context;
8810 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008811 isolate->heap()->AllocateWithContext(function,
8812 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008813 extension_object);
8814 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008815 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008816 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008821 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008822 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008823 String* name = String::cast(args[0]);
8824 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008825 JSFunction* function;
8826 if (args[2]->IsSmi()) {
8827 // A smi sentinel indicates a context nested inside global code rather
8828 // than some function. There is a canonical empty function that can be
8829 // gotten from the global context.
8830 function = isolate->context()->global_context()->closure();
8831 } else {
8832 function = JSFunction::cast(args[2]);
8833 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008834 Context* context;
8835 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008836 isolate->heap()->AllocateCatchContext(function,
8837 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008838 name,
8839 thrown_object);
8840 if (!maybe_context->To(&context)) return maybe_context;
8841 isolate->set_context(context);
8842 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008843}
8844
8845
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008846RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8847 NoHandleAllocation ha;
8848 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008849 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008850 JSFunction* function;
8851 if (args[1]->IsSmi()) {
8852 // A smi sentinel indicates a context nested inside global code rather
8853 // than some function. There is a canonical empty function that can be
8854 // gotten from the global context.
8855 function = isolate->context()->global_context()->closure();
8856 } else {
8857 function = JSFunction::cast(args[1]);
8858 }
8859 Context* context;
8860 MaybeObject* maybe_context =
8861 isolate->heap()->AllocateBlockContext(function,
8862 isolate->context(),
8863 scope_info);
8864 if (!maybe_context->To(&context)) return maybe_context;
8865 isolate->set_context(context);
8866 return context;
8867}
8868
8869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008870RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872 ASSERT(args.length() == 2);
8873
8874 CONVERT_ARG_CHECKED(Context, context, 0);
8875 CONVERT_ARG_CHECKED(String, name, 1);
8876
8877 int index;
8878 PropertyAttributes attributes;
8879 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008880 BindingFlags binding_flags;
8881 Handle<Object> holder = context->Lookup(name,
8882 flags,
8883 &index,
8884 &attributes,
8885 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008887 // If the slot was not found the result is true.
8888 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890 }
8891
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008892 // If the slot was found in a context, it should be DONT_DELETE.
8893 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008894 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008895 }
8896
8897 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008898 // the global object, or the subject of a with. Try to delete it
8899 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008900 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008901 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902}
8903
8904
ager@chromium.orga1645e22009-09-09 19:27:10 +00008905// A mechanism to return a pair of Object pointers in registers (if possible).
8906// How this is achieved is calling convention-dependent.
8907// All currently supported x86 compiles uses calling conventions that are cdecl
8908// variants where a 64-bit value is returned in two 32-bit registers
8909// (edx:eax on ia32, r1:r0 on ARM).
8910// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8911// In Win64 calling convention, a struct of two pointers is returned in memory,
8912// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008913#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008914struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008915 MaybeObject* x;
8916 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008917};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008918
lrn@chromium.org303ada72010-10-27 09:33:13 +00008919static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008920 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008921 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8922 // In Win64 they are assigned to a hidden first argument.
8923 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008924}
8925#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008926typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008927static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008929 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008931#endif
8932
8933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934static inline MaybeObject* Unhole(Heap* heap,
8935 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008936 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008937 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8938 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940}
8941
8942
danno@chromium.org40cb8782011-05-25 07:58:50 +00008943static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8944 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008945 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008946 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008947 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008948 JSFunction* context_extension_function =
8949 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008950 // If the holder isn't a context extension object, we just return it
8951 // as the receiver. This allows arguments objects to be used as
8952 // receivers, but only if they are put in the context scope chain
8953 // explicitly via a with-statement.
8954 Object* constructor = holder->map()->constructor();
8955 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008956 // Fall back to using the global object as the implicit receiver if
8957 // the property turns out to be a local variable allocated in a
8958 // context extension object - introduced via eval. Implicit global
8959 // receivers are indicated with the hole value.
8960 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008961}
8962
8963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964static ObjectPair LoadContextSlotHelper(Arguments args,
8965 Isolate* isolate,
8966 bool throw_error) {
8967 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008968 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008970 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008971 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008972 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008974 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975
8976 int index;
8977 PropertyAttributes attributes;
8978 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008979 BindingFlags binding_flags;
8980 Handle<Object> holder = context->Lookup(name,
8981 flags,
8982 &index,
8983 &attributes,
8984 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008986 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008987 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008988 ASSERT(holder->IsContext());
8989 // If the "property" we were looking for is a local variable, the
8990 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008991 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008992 // Use the hole as the receiver to signal that the receiver is implicit
8993 // and that the global receiver should be used (as distinguished from an
8994 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008995 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008996 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008997 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008998 switch (binding_flags) {
8999 case MUTABLE_CHECK_INITIALIZED:
9000 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9001 if (value->IsTheHole()) {
9002 Handle<Object> reference_error =
9003 isolate->factory()->NewReferenceError("not_defined",
9004 HandleVector(&name, 1));
9005 return MakePair(isolate->Throw(*reference_error), NULL);
9006 }
9007 // FALLTHROUGH
9008 case MUTABLE_IS_INITIALIZED:
9009 case IMMUTABLE_IS_INITIALIZED:
9010 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9011 ASSERT(!value->IsTheHole());
9012 return MakePair(value, *receiver);
9013 case IMMUTABLE_CHECK_INITIALIZED:
9014 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9015 case MISSING_BINDING:
9016 UNREACHABLE();
9017 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 }
9020
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009021 // Otherwise, if the slot was found the holder is a context extension
9022 // object, subject of a with, or a global object. We read the named
9023 // property from it.
9024 if (!holder.is_null()) {
9025 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9026 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009027 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009028 Handle<Object> receiver_handle(object->IsGlobalObject()
9029 ? GlobalObject::cast(*object)->global_receiver()
9030 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009031
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009032 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009033 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009034 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009035 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036 }
9037
9038 if (throw_error) {
9039 // The property doesn't exist - throw exception.
9040 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009041 isolate->factory()->NewReferenceError("not_defined",
9042 HandleVector(&name, 1));
9043 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009045 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 return MakePair(isolate->heap()->undefined_value(),
9047 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048 }
9049}
9050
9051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009052RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054}
9055
9056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009057RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059}
9060
9061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009062RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009064 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009068 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009069 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9070 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9071 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009072
9073 int index;
9074 PropertyAttributes attributes;
9075 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009076 BindingFlags binding_flags;
9077 Handle<Object> holder = context->Lookup(name,
9078 flags,
9079 &index,
9080 &attributes,
9081 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082
9083 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009084 // The property was found in a context slot.
9085 Handle<Context> context = Handle<Context>::cast(holder);
9086 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9087 context->get(index)->IsTheHole()) {
9088 Handle<Object> error =
9089 isolate->factory()->NewReferenceError("not_defined",
9090 HandleVector(&name, 1));
9091 return isolate->Throw(*error);
9092 }
9093 // Ignore if read_only variable.
9094 if ((attributes & READ_ONLY) == 0) {
9095 // Context is a fixed array and set cannot fail.
9096 context->set(index, *value);
9097 } else if (strict_mode == kStrictMode) {
9098 // Setting read only property in strict mode.
9099 Handle<Object> error =
9100 isolate->factory()->NewTypeError("strict_cannot_assign",
9101 HandleVector(&name, 1));
9102 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103 }
9104 return *value;
9105 }
9106
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009107 // Slow case: The property is not in a context slot. It is either in a
9108 // context extension object, a property of the subject of a with, or a
9109 // property of the global object.
9110 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009112 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009113 // The property exists on the holder.
9114 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009116 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009118
9119 if (strict_mode == kStrictMode) {
9120 // Throw in strict mode (assignment to undefined variable).
9121 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009122 isolate->factory()->NewReferenceError(
9123 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009124 return isolate->Throw(*error);
9125 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009126 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009128 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 }
9130
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009131 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009132 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009133 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009134 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009136 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009137 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009138 // Setting read only property in strict mode.
9139 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 isolate->factory()->NewTypeError(
9141 "strict_cannot_assign", HandleVector(&name, 1));
9142 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143 }
9144 return *value;
9145}
9146
9147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009148RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009149 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 ASSERT(args.length() == 1);
9151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153}
9154
9155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009156RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 ASSERT(args.length() == 1);
9159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161}
9162
9163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009164RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009165 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009166 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009167}
9168
9169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009170RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009171 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009172 ASSERT(args.length() == 1);
9173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009174 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009176 isolate->factory()->NewReferenceError("not_defined",
9177 HandleVector(&name, 1));
9178 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179}
9180
9181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009182RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009183 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184
9185 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 if (isolate->stack_guard()->IsStackOverflow()) {
9187 NoHandleAllocation na;
9188 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009189 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009191 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192}
9193
9194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195static int StackSize() {
9196 int n = 0;
9197 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9198 return n;
9199}
9200
9201
9202static void PrintTransition(Object* result) {
9203 // indentation
9204 { const int nmax = 80;
9205 int n = StackSize();
9206 if (n <= nmax)
9207 PrintF("%4d:%*s", n, n, "");
9208 else
9209 PrintF("%4d:%*s", n, nmax, "...");
9210 }
9211
9212 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009213 JavaScriptFrame::PrintTop(stdout, true, false);
9214 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009215 } else {
9216 // function result
9217 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009218 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 PrintF("\n");
9220 }
9221}
9222
9223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009224RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009225 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 NoHandleAllocation ha;
9227 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009228 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229}
9230
9231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009232RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009233 NoHandleAllocation ha;
9234 PrintTransition(args[0]);
9235 return args[0]; // return TOS
9236}
9237
9238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009239RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009240 NoHandleAllocation ha;
9241 ASSERT(args.length() == 1);
9242
9243#ifdef DEBUG
9244 if (args[0]->IsString()) {
9245 // If we have a string, assume it's a code "marker"
9246 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009247 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009249 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9250 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 } else {
9252 PrintF("DebugPrint: ");
9253 }
9254 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009255 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009256 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009257 HeapObject::cast(args[0])->map()->Print();
9258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009260 // ShortPrint is available in release mode. Print is not.
9261 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262#endif
9263 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009264 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265
9266 return args[0]; // return TOS
9267}
9268
9269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009270RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009271 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009273 isolate->PrintStack();
9274 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275}
9276
9277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009278RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009280 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281
9282 // According to ECMA-262, section 15.9.1, page 117, the precision of
9283 // the number in a Date object representing a particular instant in
9284 // time is milliseconds. Therefore, we floor the result of getting
9285 // the OS time.
9286 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009287 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288}
9289
9290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009291RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009292 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009293 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009295 CONVERT_ARG_CHECKED(String, str, 0);
9296 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009298 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009299
9300 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009301 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009302 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009303 RUNTIME_ASSERT(output->HasFastElements());
9304
9305 AssertNoAllocation no_allocation;
9306
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009307 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009308 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9309 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009310 String::FlatContent str_content = str->GetFlatContent();
9311 if (str_content.IsAscii()) {
9312 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009313 output_array,
9314 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009316 ASSERT(str_content.IsTwoByte());
9317 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009318 output_array,
9319 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009320 }
9321
9322 if (result) {
9323 return *output;
9324 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009326 }
9327}
9328
9329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009330RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331 NoHandleAllocation ha;
9332 ASSERT(args.length() == 1);
9333
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009334 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009335 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009336 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337}
9338
9339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009340RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009342 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009344 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345}
9346
9347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009348RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 NoHandleAllocation ha;
9350 ASSERT(args.length() == 1);
9351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354}
9355
9356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009357RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009358 ASSERT(args.length() == 1);
9359 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009361 return JSGlobalObject::cast(global)->global_receiver();
9362}
9363
9364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009365RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009367 ASSERT_EQ(1, args.length());
9368 CONVERT_ARG_CHECKED(String, source, 0);
9369
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009370 source = Handle<String>(source->TryFlattenGetString());
9371 // Optimized fast case where we only have ascii characters.
9372 Handle<Object> result;
9373 if (source->IsSeqAsciiString()) {
9374 result = JsonParser<true>::Parse(source);
9375 } else {
9376 result = JsonParser<false>::Parse(source);
9377 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009378 if (result.is_null()) {
9379 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009380 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009381 return Failure::Exception();
9382 }
9383 return *result;
9384}
9385
9386
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009387bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9388 Handle<Context> context) {
9389 if (context->allow_code_gen_from_strings()->IsFalse()) {
9390 // Check with callback if set.
9391 AllowCodeGenerationFromStringsCallback callback =
9392 isolate->allow_code_gen_callback();
9393 if (callback == NULL) {
9394 // No callback set and code generation disallowed.
9395 return false;
9396 } else {
9397 // Callback set. Let it decide if code generation is allowed.
9398 VMState state(isolate, EXTERNAL);
9399 return callback(v8::Utils::ToLocal(context));
9400 }
9401 }
9402 return true;
9403}
9404
9405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009406RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009407 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009408 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009409 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009410
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009411 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009412 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009413
9414 // Check if global context allows code generation from
9415 // strings. Throw an exception if it doesn't.
9416 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9417 return isolate->Throw(*isolate->factory()->NewError(
9418 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9419 }
9420
9421 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009422 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009423 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009424 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9427 context,
9428 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009429 return *fun;
9430}
9431
9432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433static ObjectPair CompileGlobalEval(Isolate* isolate,
9434 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009435 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009436 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009437 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009438 Handle<Context> context = Handle<Context>(isolate->context());
9439 Handle<Context> global_context = Handle<Context>(context->global_context());
9440
9441 // Check if global context allows code generation from
9442 // strings. Throw an exception if it doesn't.
9443 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9444 isolate->Throw(*isolate->factory()->NewError(
9445 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9446 return MakePair(Failure::Exception(), NULL);
9447 }
9448
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009449 // Deal with a normal eval call with a string argument. Compile it
9450 // and return the compiled function bound in the local context.
9451 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9452 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009453 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009454 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009455 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009456 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009457 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 Handle<JSFunction> compiled =
9459 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009460 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009461 return MakePair(*compiled, *receiver);
9462}
9463
9464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009465RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009466 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009469 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009470
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009471 // If "eval" didn't refer to the original GlobalEval, it's not a
9472 // direct call to eval.
9473 // (And even if it is, but the first argument isn't a string, just let
9474 // execution default to an indirect call to eval, which will also return
9475 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009476 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009477 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009478 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009479 }
9480
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009481 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009482 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009483 return CompileGlobalEval(isolate,
9484 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009485 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009486 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009487 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009488}
9489
9490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009491RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 // This utility adjusts the property attributes for newly created Function
9493 // object ("new Function(...)") by changing the map.
9494 // All it does is changing the prototype property to enumerable
9495 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009496 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 ASSERT(args.length() == 1);
9498 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009499
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009500 Handle<Map> map = func->shared()->is_classic_mode()
9501 ? isolate->function_instance_map()
9502 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503
9504 ASSERT(func->map()->instance_type() == map->instance_type());
9505 ASSERT(func->map()->instance_size() == map->instance_size());
9506 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 return *func;
9508}
9509
9510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009511RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009512 // Allocate a block of memory in NewSpace (filled with a filler).
9513 // Use as fallback for allocation in generated code when NewSpace
9514 // is full.
9515 ASSERT(args.length() == 1);
9516 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9517 int size = size_smi->value();
9518 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9519 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009520 Heap* heap = isolate->heap();
9521 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009522 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009523 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009524 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009525 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009527 }
9528 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009529 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009530}
9531
9532
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009533// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009534// array. Returns true if the element was pushed on the stack and
9535// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009536RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009537 ASSERT(args.length() == 2);
9538 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009539 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009540 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009541 int length = Smi::cast(array->length())->value();
9542 FixedArray* elements = FixedArray::cast(array->elements());
9543 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009545 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009546 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009547 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009548 { MaybeObject* maybe_obj =
9549 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009550 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9551 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009553}
9554
9555
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009556/**
9557 * A simple visitor visits every element of Array's.
9558 * The backend storage can be a fixed array for fast elements case,
9559 * or a dictionary for sparse array. Since Dictionary is a subtype
9560 * of FixedArray, the class can be used by both fast and slow cases.
9561 * The second parameter of the constructor, fast_elements, specifies
9562 * whether the storage is a FixedArray or Dictionary.
9563 *
9564 * An index limit is used to deal with the situation that a result array
9565 * length overflows 32-bit non-negative integer.
9566 */
9567class ArrayConcatVisitor {
9568 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 ArrayConcatVisitor(Isolate* isolate,
9570 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009571 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572 isolate_(isolate),
9573 storage_(Handle<FixedArray>::cast(
9574 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009575 index_offset_(0u),
9576 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009577
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009578 ~ArrayConcatVisitor() {
9579 clear_storage();
9580 }
9581
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009582 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009583 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009584 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009585
9586 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009587 if (index < static_cast<uint32_t>(storage_->length())) {
9588 storage_->set(index, *elm);
9589 return;
9590 }
9591 // Our initial estimate of length was foiled, possibly by
9592 // getters on the arrays increasing the length of later arrays
9593 // during iteration.
9594 // This shouldn't happen in anything but pathological cases.
9595 SetDictionaryMode(index);
9596 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009597 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009599 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009600 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009603 // Dictionary needed to grow.
9604 clear_storage();
9605 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009606 }
9607}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009608
9609 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009610 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9611 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009612 } else {
9613 index_offset_ += delta;
9614 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009615 }
9616
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009619 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009621 Handle<Map> map;
9622 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009623 map = isolate_->factory()->GetElementsTransitionMap(array,
9624 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009626 map = isolate_->factory()->GetElementsTransitionMap(array,
9627 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009628 }
9629 array->set_map(*map);
9630 array->set_length(*length);
9631 array->set_elements(*storage_);
9632 return array;
9633 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009634
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009635 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 // Convert storage to dictionary mode.
9637 void SetDictionaryMode(uint32_t index) {
9638 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009639 Handle<FixedArray> current_storage(*storage_);
9640 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009642 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9643 for (uint32_t i = 0; i < current_length; i++) {
9644 HandleScope loop_scope;
9645 Handle<Object> element(current_storage->get(i));
9646 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009647 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009648 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009649 if (!new_storage.is_identical_to(slow_storage)) {
9650 slow_storage = loop_scope.CloseAndEscape(new_storage);
9651 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 }
9653 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009654 clear_storage();
9655 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 fast_elements_ = false;
9657 }
9658
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009659 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009660 isolate_->global_handles()->Destroy(
9661 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009662 }
9663
9664 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009665 storage_ = Handle<FixedArray>::cast(
9666 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009667 }
9668
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009669 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009670 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 // Index after last seen index. Always less than or equal to
9672 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009673 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009674 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009675};
9676
9677
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009678static uint32_t EstimateElementCount(Handle<JSArray> array) {
9679 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9680 int element_count = 0;
9681 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009682 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009683 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009684 // Fast elements can't have lengths that are not representable by
9685 // a 32-bit signed integer.
9686 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9687 int fast_length = static_cast<int>(length);
9688 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9689 for (int i = 0; i < fast_length; i++) {
9690 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009691 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009692 break;
9693 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009694 case FAST_DOUBLE_ELEMENTS:
9695 // TODO(1810): Decide if it's worthwhile to implement this.
9696 UNREACHABLE();
9697 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009698 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 Handle<NumberDictionary> dictionary(
9700 NumberDictionary::cast(array->elements()));
9701 int capacity = dictionary->Capacity();
9702 for (int i = 0; i < capacity; i++) {
9703 Handle<Object> key(dictionary->KeyAt(i));
9704 if (dictionary->IsKey(*key)) {
9705 element_count++;
9706 }
9707 }
9708 break;
9709 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009710 case NON_STRICT_ARGUMENTS_ELEMENTS:
9711 case EXTERNAL_BYTE_ELEMENTS:
9712 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9713 case EXTERNAL_SHORT_ELEMENTS:
9714 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9715 case EXTERNAL_INT_ELEMENTS:
9716 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9717 case EXTERNAL_FLOAT_ELEMENTS:
9718 case EXTERNAL_DOUBLE_ELEMENTS:
9719 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009720 // External arrays are always dense.
9721 return length;
9722 }
9723 // As an estimate, we assume that the prototype doesn't contain any
9724 // inherited elements.
9725 return element_count;
9726}
9727
9728
9729
9730template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731static void IterateExternalArrayElements(Isolate* isolate,
9732 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 bool elements_are_ints,
9734 bool elements_are_guaranteed_smis,
9735 ArrayConcatVisitor* visitor) {
9736 Handle<ExternalArrayClass> array(
9737 ExternalArrayClass::cast(receiver->elements()));
9738 uint32_t len = static_cast<uint32_t>(array->length());
9739
9740 ASSERT(visitor != NULL);
9741 if (elements_are_ints) {
9742 if (elements_are_guaranteed_smis) {
9743 for (uint32_t j = 0; j < len; j++) {
9744 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009745 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 visitor->visit(j, e);
9747 }
9748 } else {
9749 for (uint32_t j = 0; j < len; j++) {
9750 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009751 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009752 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9753 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9754 visitor->visit(j, e);
9755 } else {
9756 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009757 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009758 visitor->visit(j, e);
9759 }
9760 }
9761 }
9762 } else {
9763 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009764 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009765 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 visitor->visit(j, e);
9767 }
9768 }
9769}
9770
9771
9772// Used for sorting indices in a List<uint32_t>.
9773static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9774 uint32_t a = *ap;
9775 uint32_t b = *bp;
9776 return (a == b) ? 0 : (a < b) ? -1 : 1;
9777}
9778
9779
9780static void CollectElementIndices(Handle<JSObject> object,
9781 uint32_t range,
9782 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009783 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009785 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009786 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009787 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9788 uint32_t length = static_cast<uint32_t>(elements->length());
9789 if (range < length) length = range;
9790 for (uint32_t i = 0; i < length; i++) {
9791 if (!elements->get(i)->IsTheHole()) {
9792 indices->Add(i);
9793 }
9794 }
9795 break;
9796 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009797 case FAST_DOUBLE_ELEMENTS: {
9798 // TODO(1810): Decide if it's worthwhile to implement this.
9799 UNREACHABLE();
9800 break;
9801 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009802 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009803 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009804 uint32_t capacity = dict->Capacity();
9805 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009806 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009807 Handle<Object> k(dict->KeyAt(j));
9808 if (dict->IsKey(*k)) {
9809 ASSERT(k->IsNumber());
9810 uint32_t index = static_cast<uint32_t>(k->Number());
9811 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009812 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009813 }
9814 }
9815 }
9816 break;
9817 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 default: {
9819 int dense_elements_length;
9820 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009821 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009822 dense_elements_length =
9823 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 break;
9825 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009826 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009827 dense_elements_length =
9828 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009829 break;
9830 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009831 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009832 dense_elements_length =
9833 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 break;
9835 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009856 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009857 dense_elements_length =
9858 ExternalFloatArray::cast(object->elements())->length();
9859 break;
9860 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009862 dense_elements_length =
9863 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 break;
9865 }
9866 default:
9867 UNREACHABLE();
9868 dense_elements_length = 0;
9869 break;
9870 }
9871 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9872 if (range <= length) {
9873 length = range;
9874 // We will add all indices, so we might as well clear it first
9875 // and avoid duplicates.
9876 indices->Clear();
9877 }
9878 for (uint32_t i = 0; i < length; i++) {
9879 indices->Add(i);
9880 }
9881 if (length == range) return; // All indices accounted for already.
9882 break;
9883 }
9884 }
9885
9886 Handle<Object> prototype(object->GetPrototype());
9887 if (prototype->IsJSObject()) {
9888 // The prototype will usually have no inherited element indices,
9889 // but we have to check.
9890 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9891 }
9892}
9893
9894
9895/**
9896 * A helper function that visits elements of a JSArray in numerical
9897 * order.
9898 *
9899 * The visitor argument called for each existing element in the array
9900 * with the element index and the element's value.
9901 * Afterwards it increments the base-index of the visitor by the array
9902 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009903 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009904 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009905static bool IterateElements(Isolate* isolate,
9906 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 ArrayConcatVisitor* visitor) {
9908 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9909 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009910 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009911 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009912 // Run through the elements FixedArray and use HasElement and GetElement
9913 // to check the prototype for missing elements.
9914 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9915 int fast_length = static_cast<int>(length);
9916 ASSERT(fast_length <= elements->length());
9917 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009918 HandleScope loop_scope(isolate);
9919 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009920 if (!element_value->IsTheHole()) {
9921 visitor->visit(j, element_value);
9922 } else if (receiver->HasElement(j)) {
9923 // Call GetElement on receiver, not its prototype, or getters won't
9924 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009925 element_value = Object::GetElement(receiver, j);
9926 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 visitor->visit(j, element_value);
9928 }
9929 }
9930 break;
9931 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009932 case FAST_DOUBLE_ELEMENTS: {
9933 // TODO(1810): Decide if it's worthwhile to implement this.
9934 UNREACHABLE();
9935 break;
9936 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009937 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009938 Handle<NumberDictionary> dict(receiver->element_dictionary());
9939 List<uint32_t> indices(dict->Capacity() / 2);
9940 // Collect all indices in the object and the prototypes less
9941 // than length. This might introduce duplicates in the indices list.
9942 CollectElementIndices(receiver, length, &indices);
9943 indices.Sort(&compareUInt32);
9944 int j = 0;
9945 int n = indices.length();
9946 while (j < n) {
9947 HandleScope loop_scope;
9948 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009949 Handle<Object> element = Object::GetElement(receiver, index);
9950 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009951 visitor->visit(index, element);
9952 // Skip to next different index (i.e., omit duplicates).
9953 do {
9954 j++;
9955 } while (j < n && indices[j] == index);
9956 }
9957 break;
9958 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009959 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009960 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9961 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009962 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009963 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009964 visitor->visit(j, e);
9965 }
9966 break;
9967 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009968 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009969 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009971 break;
9972 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009973 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009974 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009976 break;
9977 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009978 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 break;
9997 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009998 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 break;
10002 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010004 IterateExternalArrayElements<ExternalDoubleArray, double>(
10005 isolate, receiver, false, false, visitor);
10006 break;
10007 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010008 default:
10009 UNREACHABLE();
10010 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010011 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010013 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010014}
10015
10016
10017/**
10018 * Array::concat implementation.
10019 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010021 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010022 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010023RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010024 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010026
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10028 int argument_count = static_cast<int>(arguments->length()->Number());
10029 RUNTIME_ASSERT(arguments->HasFastElements());
10030 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010031
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 // Pass 1: estimate the length and number of elements of the result.
10033 // The actual length can be larger if any of the arguments have getters
10034 // that mutate other arguments (but will otherwise be precise).
10035 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010036
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 uint32_t estimate_result_length = 0;
10038 uint32_t estimate_nof_elements = 0;
10039 {
10040 for (int i = 0; i < argument_count; i++) {
10041 HandleScope loop_scope;
10042 Handle<Object> obj(elements->get(i));
10043 uint32_t length_estimate;
10044 uint32_t element_estimate;
10045 if (obj->IsJSArray()) {
10046 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010047 // TODO(1810): Find out if it's worthwhile to properly support
10048 // arbitrary ElementsKinds. For now, pessimistically transition to
10049 // FAST_ELEMENTS.
10050 if (array->HasFastDoubleElements()) {
10051 array = Handle<JSArray>::cast(
10052 TransitionElementsKind(array, FAST_ELEMENTS));
10053 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 length_estimate =
10055 static_cast<uint32_t>(array->length()->Number());
10056 element_estimate =
10057 EstimateElementCount(array);
10058 } else {
10059 length_estimate = 1;
10060 element_estimate = 1;
10061 }
10062 // Avoid overflows by capping at kMaxElementCount.
10063 if (JSObject::kMaxElementCount - estimate_result_length <
10064 length_estimate) {
10065 estimate_result_length = JSObject::kMaxElementCount;
10066 } else {
10067 estimate_result_length += length_estimate;
10068 }
10069 if (JSObject::kMaxElementCount - estimate_nof_elements <
10070 element_estimate) {
10071 estimate_nof_elements = JSObject::kMaxElementCount;
10072 } else {
10073 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010074 }
10075 }
10076 }
10077
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010078 // If estimated number of elements is more than half of length, a
10079 // fixed array (fast case) is more time and space-efficient than a
10080 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010081 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010082
10083 Handle<FixedArray> storage;
10084 if (fast_case) {
10085 // The backing storage array must have non-existing elements to
10086 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 storage = isolate->factory()->NewFixedArrayWithHoles(
10088 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089 } else {
10090 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10091 uint32_t at_least_space_for = estimate_nof_elements +
10092 (estimate_nof_elements >> 2);
10093 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010095 }
10096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010097 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010098
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010099 for (int i = 0; i < argument_count; i++) {
10100 Handle<Object> obj(elements->get(i));
10101 if (obj->IsJSArray()) {
10102 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010104 return Failure::Exception();
10105 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010106 } else {
10107 visitor.visit(0, obj);
10108 visitor.increase_index_offset(1);
10109 }
10110 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010111
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010112 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113}
10114
10115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010116// This will not allocate (flatten the string), but it may run
10117// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010118RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119 NoHandleAllocation ha;
10120 ASSERT(args.length() == 1);
10121
10122 CONVERT_CHECKED(String, string, args[0]);
10123 StringInputBuffer buffer(string);
10124 while (buffer.has_more()) {
10125 uint16_t character = buffer.GetNext();
10126 PrintF("%c", character);
10127 }
10128 return string;
10129}
10130
ager@chromium.org5ec48922009-05-05 07:25:34 +000010131// Moves all own elements of an object, that are below a limit, to positions
10132// starting at zero. All undefined values are placed after non-undefined values,
10133// and are followed by non-existing element. Does not change the length
10134// property.
10135// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010137 ASSERT(args.length() == 2);
10138 CONVERT_CHECKED(JSObject, object, args[0]);
10139 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10140 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141}
10142
10143
10144// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010145RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010146 ASSERT(args.length() == 2);
10147 CONVERT_CHECKED(JSArray, from, args[0]);
10148 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010149 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010150 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010151 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10153 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010154 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010155 } else if (new_elements->map() ==
10156 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010157 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010158 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010159 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010160 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010161 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010162 Object* new_map;
10163 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010164 to->set_map(Map::cast(new_map));
10165 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010166 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010167 Object* obj;
10168 { MaybeObject* maybe_obj = from->ResetElements();
10169 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010171 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 return to;
10173}
10174
10175
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010176// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010177RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010179 CONVERT_CHECKED(JSObject, object, args[0]);
10180 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010182 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010183 } else if (object->IsJSArray()) {
10184 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010185 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010186 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 }
10188}
10189
10190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010191RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010193
10194 ASSERT_EQ(3, args.length());
10195
ager@chromium.orgac091b72010-05-05 07:34:42 +000010196 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010197 Handle<Object> key1 = args.at<Object>(1);
10198 Handle<Object> key2 = args.at<Object>(2);
10199
10200 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010201 if (!key1->ToArrayIndex(&index1)
10202 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010203 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010204 }
10205
ager@chromium.orgac091b72010-05-05 07:34:42 +000010206 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010207 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010209 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 RETURN_IF_EMPTY_HANDLE(isolate,
10213 SetElement(jsobject, index1, tmp2, kStrictMode));
10214 RETURN_IF_EMPTY_HANDLE(isolate,
10215 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010217 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010218}
10219
10220
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010222// might have elements. Can either return keys (positive integers) or
10223// intervals (pair of a negative integer (-start-1) followed by a
10224// positive (length)) or undefined values.
10225// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010226RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010229 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010231 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 // Create an array and get all the keys into it, then remove all the
10233 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010234 bool threw = false;
10235 Handle<FixedArray> keys =
10236 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10237 if (threw) return Failure::Exception();
10238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 int keys_length = keys->length();
10240 for (int i = 0; i < keys_length; i++) {
10241 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010242 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010243 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 // Zap invalid keys.
10245 keys->set_undefined(i);
10246 }
10247 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010248 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010250 ASSERT(array->HasFastElements() ||
10251 array->HasFastSmiOnlyElements() ||
10252 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010255 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010256 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010257 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010258 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010259 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 }
10265}
10266
10267
10268// DefineAccessor takes an optional final argument which is the
10269// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10270// to the way accessors are implemented, it is set for both the getter
10271// and setter on the first call to DefineAccessor and ignored on
10272// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010273RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10275 // Compute attributes.
10276 PropertyAttributes attributes = NONE;
10277 if (args.length() == 5) {
10278 CONVERT_CHECKED(Smi, attrs, args[4]);
10279 int value = attrs->value();
10280 // Only attribute bits should be set.
10281 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10282 attributes = static_cast<PropertyAttributes>(value);
10283 }
10284
10285 CONVERT_CHECKED(JSObject, obj, args[0]);
10286 CONVERT_CHECKED(String, name, args[1]);
10287 CONVERT_CHECKED(Smi, flag, args[2]);
10288 CONVERT_CHECKED(JSFunction, fun, args[3]);
10289 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10290}
10291
10292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010293RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 ASSERT(args.length() == 3);
10295 CONVERT_CHECKED(JSObject, obj, args[0]);
10296 CONVERT_CHECKED(String, name, args[1]);
10297 CONVERT_CHECKED(Smi, flag, args[2]);
10298 return obj->LookupAccessor(name, flag->value() == 0);
10299}
10300
10301
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010302#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010303RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010304 ASSERT(args.length() == 0);
10305 return Execution::DebugBreakHelper();
10306}
10307
10308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309// Helper functions for wrapping and unwrapping stack frame ids.
10310static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010311 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 return Smi::FromInt(id >> 2);
10313}
10314
10315
10316static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10317 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10318}
10319
10320
10321// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010322// args[0]: debug event listener function to set or null or undefined for
10323// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010325RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010327 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10328 args[0]->IsUndefined() ||
10329 args[0]->IsNull());
10330 Handle<Object> callback = args.at<Object>(0);
10331 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010334 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335}
10336
10337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010338RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010339 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 isolate->stack_guard()->DebugBreak();
10341 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342}
10343
10344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345static MaybeObject* DebugLookupResultValue(Heap* heap,
10346 Object* receiver,
10347 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010348 LookupResult* result,
10349 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010350 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010352 case NORMAL:
10353 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010354 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 }
10357 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010358 case FIELD:
10359 value =
10360 JSObject::cast(
10361 result->holder())->FastPropertyAt(result->GetFieldIndex());
10362 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010363 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010364 }
10365 return value;
10366 case CONSTANT_FUNCTION:
10367 return result->GetConstantFunction();
10368 case CALLBACKS: {
10369 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010370 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010371 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10372 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010373 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010374 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010375 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010376 maybe_value = heap->isolate()->pending_exception();
10377 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010378 if (caught_exception != NULL) {
10379 *caught_exception = true;
10380 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010381 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010382 }
10383 return value;
10384 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010386 }
10387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010389 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010390 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010391 case CONSTANT_TRANSITION:
10392 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010393 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010394 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010396 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010398 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010399 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400}
10401
10402
ager@chromium.org32912102009-01-16 10:38:43 +000010403// Get debugger related details for an object property.
10404// args[0]: object holding property
10405// args[1]: name of the property
10406//
10407// The array returned contains the following information:
10408// 0: Property value
10409// 1: Property details
10410// 2: Property value is exception
10411// 3: Getter function if defined
10412// 4: Setter function if defined
10413// Items 2-4 are only filled if the property has either a getter or a setter
10414// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010415RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010416 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417
10418 ASSERT(args.length() == 2);
10419
10420 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10421 CONVERT_ARG_CHECKED(String, name, 1);
10422
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010423 // Make sure to set the current context to the context before the debugger was
10424 // entered (if the debugger is entered). The reason for switching context here
10425 // is that for some property lookups (accessors and interceptors) callbacks
10426 // into the embedding application can occour, and the embedding application
10427 // could have the assumption that its own global context is the current
10428 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010429 SaveContext save(isolate);
10430 if (isolate->debug()->InDebugger()) {
10431 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010432 }
10433
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010434 // Skip the global proxy as it has no properties and always delegates to the
10435 // real global object.
10436 if (obj->IsJSGlobalProxy()) {
10437 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10438 }
10439
10440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441 // Check if the name is trivially convertible to an index and get the element
10442 // if so.
10443 uint32_t index;
10444 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010446 Object* element_or_char;
10447 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010449 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10450 return maybe_element_or_char;
10451 }
10452 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010453 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010454 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010455 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010456 }
10457
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010458 // Find the number of objects making up this.
10459 int length = LocalPrototypeChainLength(*obj);
10460
10461 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010462 Handle<JSObject> jsproto = obj;
10463 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010464 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010465 jsproto->LocalLookup(*name, &result);
10466 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010467 // LookupResult is not GC safe as it holds raw object pointers.
10468 // GC can happen later in this code so put the required fields into
10469 // local variables using handles when required for later use.
10470 PropertyType result_type = result.type();
10471 Handle<Object> result_callback_obj;
10472 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10474 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010475 }
10476 Smi* property_details = result.GetPropertyDetails().AsSmi();
10477 // DebugLookupResultValue can cause GC so details from LookupResult needs
10478 // to be copied to handles before this.
10479 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010480 Object* raw_value;
10481 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 DebugLookupResultValue(isolate->heap(), *obj, *name,
10483 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010484 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10485 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010487
10488 // If the callback object is a fixed array then it contains JavaScript
10489 // getter and/or setter.
10490 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10491 result_callback_obj->IsFixedArray();
10492 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010494 details->set(0, *value);
10495 details->set(1, property_details);
10496 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010497 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010498 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10499 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10500 }
10501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010502 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010503 }
10504 if (i < length - 1) {
10505 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10506 }
10507 }
10508
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510}
10511
10512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010513RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515
10516 ASSERT(args.length() == 2);
10517
10518 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10519 CONVERT_ARG_CHECKED(String, name, 1);
10520
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010521 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522 obj->Lookup(*name, &result);
10523 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010526 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527}
10528
10529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530// Return the property type calculated from the property details.
10531// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010532RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 ASSERT(args.length() == 1);
10534 CONVERT_CHECKED(Smi, details, args[0]);
10535 PropertyType type = PropertyDetails(details).type();
10536 return Smi::FromInt(static_cast<int>(type));
10537}
10538
10539
10540// Return the property attribute calculated from the property details.
10541// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010542RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010543 ASSERT(args.length() == 1);
10544 CONVERT_CHECKED(Smi, details, args[0]);
10545 PropertyAttributes attributes = PropertyDetails(details).attributes();
10546 return Smi::FromInt(static_cast<int>(attributes));
10547}
10548
10549
10550// Return the property insertion index calculated from the property details.
10551// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010552RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 ASSERT(args.length() == 1);
10554 CONVERT_CHECKED(Smi, details, args[0]);
10555 int index = PropertyDetails(details).index();
10556 return Smi::FromInt(index);
10557}
10558
10559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560// Return property value from named interceptor.
10561// args[0]: object
10562// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010563RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010565 ASSERT(args.length() == 2);
10566 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10567 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10568 CONVERT_ARG_CHECKED(String, name, 1);
10569
10570 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010571 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572}
10573
10574
10575// Return element value from indexed interceptor.
10576// args[0]: object
10577// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010578RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 ASSERT(args.length() == 2);
10581 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10582 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10583 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10584
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010585 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586}
10587
10588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010589RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 ASSERT(args.length() >= 1);
10591 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010592 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 if (isolate->debug()->break_id() == 0 ||
10594 break_id != isolate->debug()->break_id()) {
10595 return isolate->Throw(
10596 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 }
10598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010599 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600}
10601
10602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605 ASSERT(args.length() == 1);
10606
10607 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010608 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010609 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10610 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010611 if (!maybe_result->ToObject(&result)) return maybe_result;
10612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613
10614 // Count all frames which are relevant to debugging stack trace.
10615 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010616 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010617 if (id == StackFrame::NO_ID) {
10618 // If there is no JavaScript stack frame count is 0.
10619 return Smi::FromInt(0);
10620 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010621
10622 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10623 n += it.frame()->GetInlineCount();
10624 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 return Smi::FromInt(n);
10626}
10627
10628
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010629class FrameInspector {
10630 public:
10631 FrameInspector(JavaScriptFrame* frame,
10632 int inlined_frame_index,
10633 Isolate* isolate)
10634 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10635 // Calculate the deoptimized frame.
10636 if (frame->is_optimized()) {
10637 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10638 frame, inlined_frame_index, isolate);
10639 }
10640 has_adapted_arguments_ = frame_->has_adapted_arguments();
10641 is_optimized_ = frame_->is_optimized();
10642 }
10643
10644 ~FrameInspector() {
10645 // Get rid of the calculated deoptimized frame if any.
10646 if (deoptimized_frame_ != NULL) {
10647 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10648 isolate_);
10649 }
10650 }
10651
10652 int GetParametersCount() {
10653 return is_optimized_
10654 ? deoptimized_frame_->parameters_count()
10655 : frame_->ComputeParametersCount();
10656 }
10657 int expression_count() { return deoptimized_frame_->expression_count(); }
10658 Object* GetFunction() {
10659 return is_optimized_
10660 ? deoptimized_frame_->GetFunction()
10661 : frame_->function();
10662 }
10663 Object* GetParameter(int index) {
10664 return is_optimized_
10665 ? deoptimized_frame_->GetParameter(index)
10666 : frame_->GetParameter(index);
10667 }
10668 Object* GetExpression(int index) {
10669 return is_optimized_
10670 ? deoptimized_frame_->GetExpression(index)
10671 : frame_->GetExpression(index);
10672 }
10673
10674 // To inspect all the provided arguments the frame might need to be
10675 // replaced with the arguments frame.
10676 void SetArgumentsFrame(JavaScriptFrame* frame) {
10677 ASSERT(has_adapted_arguments_);
10678 frame_ = frame;
10679 is_optimized_ = frame_->is_optimized();
10680 ASSERT(!is_optimized_);
10681 }
10682
10683 private:
10684 JavaScriptFrame* frame_;
10685 DeoptimizedFrameInfo* deoptimized_frame_;
10686 Isolate* isolate_;
10687 bool is_optimized_;
10688 bool has_adapted_arguments_;
10689
10690 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10691};
10692
10693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010694static const int kFrameDetailsFrameIdIndex = 0;
10695static const int kFrameDetailsReceiverIndex = 1;
10696static const int kFrameDetailsFunctionIndex = 2;
10697static const int kFrameDetailsArgumentCountIndex = 3;
10698static const int kFrameDetailsLocalCountIndex = 4;
10699static const int kFrameDetailsSourcePositionIndex = 5;
10700static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010701static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010702static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010703static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010705
10706static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10707 JavaScriptFrame* frame) {
10708 SaveContext* save = isolate->save_context();
10709 while (save != NULL && !save->IsBelowFrame(frame)) {
10710 save = save->prev();
10711 }
10712 ASSERT(save != NULL);
10713 return save;
10714}
10715
10716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717// Return an array with frame details
10718// args[0]: number: break id
10719// args[1]: number: frame index
10720//
10721// The array returned contains the following information:
10722// 0: Frame id
10723// 1: Receiver
10724// 2: Function
10725// 3: Argument count
10726// 4: Local count
10727// 5: Source position
10728// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010729// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010730// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731// Arguments name, value
10732// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010733// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010734RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010735 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736 ASSERT(args.length() == 2);
10737
10738 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010739 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010740 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10741 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010742 if (!maybe_check->ToObject(&check)) return maybe_check;
10743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010745 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746
10747 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010749 if (id == StackFrame::NO_ID) {
10750 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010751 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010752 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010753
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010754 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010757 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010759 if (index < count + it.frame()->GetInlineCount()) break;
10760 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010764 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010765 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010766 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010767 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010768 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 // Traverse the saved contexts chain to find the active context for the
10771 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010772 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773
10774 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010775 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776
10777 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010779 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010781 // Check for constructor frame. Inlined frames cannot be construct calls.
10782 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010783 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010784 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010786 // Get scope info and read from it for local variable information.
10787 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010788 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010789 Handle<ScopeInfo> scope_info(shared->scope_info());
10790 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792 // Get the locals names and values into a temporary array.
10793 //
10794 // TODO(1240907): Hide compiler-introduced stack variables
10795 // (e.g. .result)? For users of the debugger, they will probably be
10796 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010797 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010798 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010800 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010801 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010802 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010803 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010804 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010805 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010806 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010807 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010808 // Get the context containing declarations.
10809 Handle<Context> context(
10810 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010811 for (; i < scope_info->LocalCount(); ++i) {
10812 Handle<String> name(scope_info->LocalName(i));
10813 VariableMode mode;
10814 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010815 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010816 locals->set(i * 2 + 1, context->get(
10817 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 }
10819 }
10820
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010821 // Check whether this frame is positioned at return. If not top
10822 // frame or if the frame is optimized it cannot be at a return.
10823 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010824 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010826 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010827
10828 // If positioned just before return find the value to be returned and add it
10829 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010831 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010832 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010833 Address internal_frame_sp = NULL;
10834 while (!it2.done()) {
10835 if (it2.frame()->is_internal()) {
10836 internal_frame_sp = it2.frame()->sp();
10837 } else {
10838 if (it2.frame()->is_java_script()) {
10839 if (it2.frame()->id() == it.frame()->id()) {
10840 // The internal frame just before the JavaScript frame contains the
10841 // value to return on top. A debug break at return will create an
10842 // internal frame to store the return value (eax/rax/r0) before
10843 // entering the debug break exit frame.
10844 if (internal_frame_sp != NULL) {
10845 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 Handle<Object>(Memory::Object_at(internal_frame_sp),
10847 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010848 break;
10849 }
10850 }
10851 }
10852
10853 // Indicate that the previous frame was not an internal frame.
10854 internal_frame_sp = NULL;
10855 }
10856 it2.Advance();
10857 }
10858 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859
10860 // Now advance to the arguments adapter frame (if any). It contains all
10861 // the provided parameters whereas the function frame always have the number
10862 // of arguments matching the functions parameters. The rest of the
10863 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010864 if (it.frame()->has_adapted_arguments()) {
10865 it.AdvanceToArgumentsFrame();
10866 frame_inspector.SetArgumentsFrame(it.frame());
10867 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868
10869 // Find the number of arguments to fill. At least fill the number of
10870 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010871 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010872 if (argument_count < frame_inspector.GetParametersCount()) {
10873 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010875#ifdef DEBUG
10876 if (it.frame()->is_optimized()) {
10877 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10878 }
10879#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880
10881 // Calculate the size of the result.
10882 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010883 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010884 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886
10887 // Add the frame id.
10888 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10889
10890 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010891 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892
10893 // Add the arguments count.
10894 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10895
10896 // Add the locals count
10897 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010898 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899
10900 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010901 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10903 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010905 }
10906
10907 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010908 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010910 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010911 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010912
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010913 // Add flags to indicate information on whether this frame is
10914 // bit 0: invoked in the debugger context.
10915 // bit 1: optimized frame.
10916 // bit 2: inlined in optimized frame
10917 int flags = 0;
10918 if (*save->context() == *isolate->debug()->debug_context()) {
10919 flags |= 1 << 0;
10920 }
10921 if (it.frame()->is_optimized()) {
10922 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010923 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010924 }
10925 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926
10927 // Fill the dynamic part.
10928 int details_index = kFrameDetailsFirstDynamicIndex;
10929
10930 // Add arguments name and value.
10931 for (int i = 0; i < argument_count; i++) {
10932 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010933 if (i < scope_info->ParameterCount()) {
10934 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937 }
10938
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010939 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010940 if (i < it.frame()->ComputeParametersCount()) {
10941 // Get the value from the stack.
10942 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010944 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945 }
10946 }
10947
10948 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010949 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 details->set(details_index++, locals->get(i));
10951 }
10952
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010953 // Add the value being returned.
10954 if (at_return) {
10955 details->set(details_index++, *return_value);
10956 }
10957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010958 // Add the receiver (same as in function frame).
10959 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10960 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010962 if (!receiver->IsJSObject() &&
10963 shared->is_classic_mode() &&
10964 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010965 // If the receiver is not a JSObject and the function is not a
10966 // builtin or strict-mode we have hit an optimization where a
10967 // value object is not converted into a wrapped JS objects. To
10968 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 // by creating correct wrapper object based on the calling frame's
10970 // global context.
10971 it.Advance();
10972 Handle<Context> calling_frames_global_context(
10973 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 receiver =
10975 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976 }
10977 details->set(kFrameDetailsReceiverIndex, *receiver);
10978
10979 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981}
10982
10983
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010984// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010985static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010986 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010987 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010988 Handle<Context> context,
10989 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010990 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010991 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10992 VariableMode mode;
10993 InitializationFlag init_flag;
10994 int context_index = scope_info->ContextSlotIndex(
10995 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010996
whesse@chromium.org7b260152011-06-20 15:33:18 +000010997 RETURN_IF_EMPTY_HANDLE_VALUE(
10998 isolate,
10999 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011000 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011001 Handle<Object>(context->get(context_index), isolate),
11002 NONE,
11003 kNonStrictMode),
11004 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011005 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011006
11007 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008}
11009
11010
11011// Create a plain JSObject which materializes the local scope for the specified
11012// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011013static Handle<JSObject> MaterializeLocalScope(
11014 Isolate* isolate,
11015 JavaScriptFrame* frame,
11016 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011018 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011019 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011020 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011021
11022 // Allocate and initialize a JSObject with all the arguments, stack locals
11023 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011024 Handle<JSObject> local_scope =
11025 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011026
11027 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011028 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011029 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011031 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011032 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011033 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011034 NONE,
11035 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011036 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011037 }
11038
11039 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011040 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011041 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011043 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011044 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011045 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011046 NONE,
11047 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011048 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011049 }
11050
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011051 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011052 // Third fill all context locals.
11053 Handle<Context> frame_context(Context::cast(frame->context()));
11054 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011055 if (!CopyContextLocalsToScopeObject(
11056 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011057 return Handle<JSObject>();
11058 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011059
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011060 // Finally copy any properties from the function context extension.
11061 // These will be variables introduced by eval.
11062 if (function_context->closure() == *function) {
11063 if (function_context->has_extension() &&
11064 !function_context->IsGlobalContext()) {
11065 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011066 bool threw = false;
11067 Handle<FixedArray> keys =
11068 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11069 if (threw) return Handle<JSObject>();
11070
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011071 for (int i = 0; i < keys->length(); i++) {
11072 // Names of variables introduced by eval are strings.
11073 ASSERT(keys->get(i)->IsString());
11074 Handle<String> key(String::cast(keys->get(i)));
11075 RETURN_IF_EMPTY_HANDLE_VALUE(
11076 isolate,
11077 SetProperty(local_scope,
11078 key,
11079 GetProperty(ext, key),
11080 NONE,
11081 kNonStrictMode),
11082 Handle<JSObject>());
11083 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011084 }
11085 }
11086 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011087
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 return local_scope;
11089}
11090
11091
11092// Create a plain JSObject which materializes the closure content for the
11093// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011094static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11095 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011096 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011098 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011099 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100
11101 // Allocate and initialize a JSObject with all the content of theis function
11102 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 Handle<JSObject> closure_scope =
11104 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011105
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011106 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011107 if (!CopyContextLocalsToScopeObject(
11108 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011109 return Handle<JSObject>();
11110 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011111
11112 // Finally copy any properties from the function context extension. This will
11113 // be variables introduced by eval.
11114 if (context->has_extension()) {
11115 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011116 bool threw = false;
11117 Handle<FixedArray> keys =
11118 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11119 if (threw) return Handle<JSObject>();
11120
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 for (int i = 0; i < keys->length(); i++) {
11122 // Names of variables introduced by eval are strings.
11123 ASSERT(keys->get(i)->IsString());
11124 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011125 RETURN_IF_EMPTY_HANDLE_VALUE(
11126 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011127 SetProperty(closure_scope,
11128 key,
11129 GetProperty(ext, key),
11130 NONE,
11131 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011132 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011133 }
11134 }
11135
11136 return closure_scope;
11137}
11138
11139
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011140// Create a plain JSObject which materializes the scope for the specified
11141// catch context.
11142static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11143 Handle<Context> context) {
11144 ASSERT(context->IsCatchContext());
11145 Handle<String> name(String::cast(context->extension()));
11146 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11147 Handle<JSObject> catch_scope =
11148 isolate->factory()->NewJSObject(isolate->object_function());
11149 RETURN_IF_EMPTY_HANDLE_VALUE(
11150 isolate,
11151 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11152 Handle<JSObject>());
11153 return catch_scope;
11154}
11155
11156
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011157// Create a plain JSObject which materializes the block scope for the specified
11158// block context.
11159static Handle<JSObject> MaterializeBlockScope(
11160 Isolate* isolate,
11161 Handle<Context> context) {
11162 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011163 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011164
11165 // Allocate and initialize a JSObject with all the arguments, stack locals
11166 // heap locals and extension properties of the debugged function.
11167 Handle<JSObject> block_scope =
11168 isolate->factory()->NewJSObject(isolate->object_function());
11169
11170 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011171 if (!CopyContextLocalsToScopeObject(
11172 isolate, scope_info, context, block_scope)) {
11173 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011174 }
11175
11176 return block_scope;
11177}
11178
11179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011180// Iterate over the actual scopes visible from a stack frame. The iteration
11181// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011182// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011183// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011184class ScopeIterator {
11185 public:
11186 enum ScopeType {
11187 ScopeTypeGlobal = 0,
11188 ScopeTypeLocal,
11189 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011190 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011191 ScopeTypeCatch,
11192 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 };
11194
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011195 ScopeIterator(Isolate* isolate,
11196 JavaScriptFrame* frame,
11197 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011198 : isolate_(isolate),
11199 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011200 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011201 function_(JSFunction::cast(frame->function())),
11202 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011203 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011204
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011205 // Catch the case when the debugger stops in an internal function.
11206 Handle<SharedFunctionInfo> shared_info(function_->shared());
11207 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11208 if (shared_info->script() == isolate->heap()->undefined_value()) {
11209 while (context_->closure() == *function_) {
11210 context_ = Handle<Context>(context_->previous(), isolate_);
11211 }
11212 return;
11213 }
11214
11215 // Get the debug info (create it if it does not exist).
11216 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11217 // Return if ensuring debug info failed.
11218 return;
11219 }
11220 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11221
11222 // Find the break point where execution has stopped.
11223 BreakLocationIterator break_location_iterator(debug_info,
11224 ALL_BREAK_LOCATIONS);
11225 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11226 if (break_location_iterator.IsExit()) {
11227 // We are within the return sequence. At the momemt it is not possible to
11228 // get a source position which is consistent with the current scope chain.
11229 // Thus all nested with, catch and block contexts are skipped and we only
11230 // provide the function scope.
11231 if (scope_info->HasContext()) {
11232 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11233 } else {
11234 while (context_->closure() == *function_) {
11235 context_ = Handle<Context>(context_->previous(), isolate_);
11236 }
11237 }
11238 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11239 } else {
11240 // Reparse the code and analyze the scopes.
11241 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11242 Handle<Script> script(Script::cast(shared_info->script()));
11243 Scope* scope = NULL;
11244
11245 // Check whether we are in global, eval or function code.
11246 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11247 if (scope_info->Type() != FUNCTION_SCOPE) {
11248 // Global or eval code.
11249 CompilationInfo info(script);
11250 if (scope_info->Type() == GLOBAL_SCOPE) {
11251 info.MarkAsGlobal();
11252 } else {
11253 ASSERT(scope_info->Type() == EVAL_SCOPE);
11254 info.MarkAsEval();
11255 info.SetCallingContext(Handle<Context>(function_->context()));
11256 }
11257 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11258 scope = info.function()->scope();
11259 }
11260 } else {
11261 // Function code
11262 CompilationInfo info(shared_info);
11263 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11264 scope = info.function()->scope();
11265 }
11266 }
11267
11268 // Retrieve the scope chain for the current position.
11269 if (scope != NULL) {
11270 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11271 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11272 } else {
11273 // A failed reparse indicates that the preparser has diverged from the
11274 // parser or that the preparse data given to the initial parse has been
11275 // faulty. We fail in debug mode but in release mode we only provide the
11276 // information we get from the context chain but nothing about
11277 // completely stack allocated scopes or stack allocated locals.
11278 UNREACHABLE();
11279 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011280 }
11281 }
11282
11283 // More scopes?
11284 bool Done() { return context_.is_null(); }
11285
11286 // Move to the next scope.
11287 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011288 ScopeType scope_type = Type();
11289 if (scope_type == ScopeTypeGlobal) {
11290 // The global scope is always the last in the chain.
11291 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292 context_ = Handle<Context>();
11293 return;
11294 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011295 if (nested_scope_chain_.is_empty()) {
11296 context_ = Handle<Context>(context_->previous(), isolate_);
11297 } else {
11298 if (nested_scope_chain_.last()->HasContext()) {
11299 ASSERT(context_->previous() != NULL);
11300 context_ = Handle<Context>(context_->previous(), isolate_);
11301 }
11302 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011303 }
11304 }
11305
11306 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011307 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011308 if (!nested_scope_chain_.is_empty()) {
11309 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11310 switch (scope_info->Type()) {
11311 case FUNCTION_SCOPE:
11312 ASSERT(context_->IsFunctionContext() ||
11313 !scope_info->HasContext());
11314 return ScopeTypeLocal;
11315 case GLOBAL_SCOPE:
11316 ASSERT(context_->IsGlobalContext());
11317 return ScopeTypeGlobal;
11318 case WITH_SCOPE:
11319 ASSERT(context_->IsWithContext());
11320 return ScopeTypeWith;
11321 case CATCH_SCOPE:
11322 ASSERT(context_->IsCatchContext());
11323 return ScopeTypeCatch;
11324 case BLOCK_SCOPE:
11325 ASSERT(!scope_info->HasContext() ||
11326 context_->IsBlockContext());
11327 return ScopeTypeBlock;
11328 case EVAL_SCOPE:
11329 UNREACHABLE();
11330 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011331 }
11332 if (context_->IsGlobalContext()) {
11333 ASSERT(context_->global()->IsGlobalObject());
11334 return ScopeTypeGlobal;
11335 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011336 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011337 return ScopeTypeClosure;
11338 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011339 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011340 return ScopeTypeCatch;
11341 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011342 if (context_->IsBlockContext()) {
11343 return ScopeTypeBlock;
11344 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011345 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011346 return ScopeTypeWith;
11347 }
11348
11349 // Return the JavaScript object with the content of the current scope.
11350 Handle<JSObject> ScopeObject() {
11351 switch (Type()) {
11352 case ScopeIterator::ScopeTypeGlobal:
11353 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011354 case ScopeIterator::ScopeTypeLocal:
11355 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011356 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011357 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011358 case ScopeIterator::ScopeTypeWith:
11359 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011360 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11361 case ScopeIterator::ScopeTypeCatch:
11362 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011363 case ScopeIterator::ScopeTypeClosure:
11364 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011366 case ScopeIterator::ScopeTypeBlock:
11367 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 }
11369 UNREACHABLE();
11370 return Handle<JSObject>();
11371 }
11372
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011373 Handle<ScopeInfo> CurrentScopeInfo() {
11374 if (!nested_scope_chain_.is_empty()) {
11375 return nested_scope_chain_.last();
11376 } else if (context_->IsBlockContext()) {
11377 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11378 } else if (context_->IsFunctionContext()) {
11379 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11380 }
11381 return Handle<ScopeInfo>::null();
11382 }
11383
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011384 // Return the context for this scope. For the local context there might not
11385 // be an actual context.
11386 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011387 if (Type() == ScopeTypeGlobal ||
11388 nested_scope_chain_.is_empty()) {
11389 return context_;
11390 } else if (nested_scope_chain_.last()->HasContext()) {
11391 return context_;
11392 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011393 return Handle<Context>();
11394 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011395 }
11396
11397#ifdef DEBUG
11398 // Debug print of the content of the current scope.
11399 void DebugPrint() {
11400 switch (Type()) {
11401 case ScopeIterator::ScopeTypeGlobal:
11402 PrintF("Global:\n");
11403 CurrentContext()->Print();
11404 break;
11405
11406 case ScopeIterator::ScopeTypeLocal: {
11407 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011408 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011409 if (!CurrentContext().is_null()) {
11410 CurrentContext()->Print();
11411 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011412 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011413 if (extension->IsJSContextExtensionObject()) {
11414 extension->Print();
11415 }
11416 }
11417 }
11418 break;
11419 }
11420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011421 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011422 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011423 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011424 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011425
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011426 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011427 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011428 CurrentContext()->extension()->Print();
11429 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011430 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011432 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011433 PrintF("Closure:\n");
11434 CurrentContext()->Print();
11435 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011436 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437 if (extension->IsJSContextExtensionObject()) {
11438 extension->Print();
11439 }
11440 }
11441 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011442
11443 default:
11444 UNREACHABLE();
11445 }
11446 PrintF("\n");
11447 }
11448#endif
11449
11450 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011451 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011453 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011454 Handle<JSFunction> function_;
11455 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011456 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011457
11458 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11459};
11460
11461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011462RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011464 ASSERT(args.length() == 2);
11465
11466 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011467 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011468 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11469 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011470 if (!maybe_check->ToObject(&check)) return maybe_check;
11471 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11473
11474 // Get the frame where the debugging is performed.
11475 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011476 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011477 JavaScriptFrame* frame = it.frame();
11478
11479 // Count the visible scopes.
11480 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011481 for (ScopeIterator it(isolate, frame, 0);
11482 !it.Done();
11483 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011484 n++;
11485 }
11486
11487 return Smi::FromInt(n);
11488}
11489
11490
11491static const int kScopeDetailsTypeIndex = 0;
11492static const int kScopeDetailsObjectIndex = 1;
11493static const int kScopeDetailsSize = 2;
11494
11495// Return an array with scope details
11496// args[0]: number: break id
11497// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011498// args[2]: number: inlined frame index
11499// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011500//
11501// The array returned contains the following information:
11502// 0: Scope type
11503// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011504RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011506 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011507
11508 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011509 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011510 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11511 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011512 if (!maybe_check->ToObject(&check)) return maybe_check;
11513 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011514 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011515 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11516 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011517
11518 // Get the frame where the debugging is performed.
11519 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011520 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011521 JavaScriptFrame* frame = frame_it.frame();
11522
11523 // Find the requested scope.
11524 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011525 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011526 for (; !it.Done() && n < index; it.Next()) {
11527 n++;
11528 }
11529 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531 }
11532
11533 // Calculate the size of the result.
11534 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011535 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536
11537 // Fill in scope details.
11538 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011539 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011541 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011544}
11545
11546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011549 ASSERT(args.length() == 0);
11550
11551#ifdef DEBUG
11552 // Print the scopes for the top frame.
11553 StackFrameLocator locator;
11554 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011555 for (ScopeIterator it(isolate, frame, 0);
11556 !it.Done();
11557 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011558 it.DebugPrint();
11559 }
11560#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011561 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011562}
11563
11564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011565RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011567 ASSERT(args.length() == 1);
11568
11569 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011570 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011571 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11572 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011573 if (!maybe_result->ToObject(&result)) return maybe_result;
11574 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011575
11576 // Count all archived V8 threads.
11577 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 for (ThreadState* thread =
11579 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011580 thread != NULL;
11581 thread = thread->Next()) {
11582 n++;
11583 }
11584
11585 // Total number of threads is current thread and archived threads.
11586 return Smi::FromInt(n + 1);
11587}
11588
11589
11590static const int kThreadDetailsCurrentThreadIndex = 0;
11591static const int kThreadDetailsThreadIdIndex = 1;
11592static const int kThreadDetailsSize = 2;
11593
11594// Return an array with thread details
11595// args[0]: number: break id
11596// args[1]: number: thread index
11597//
11598// The array returned contains the following information:
11599// 0: Is current thread?
11600// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011603 ASSERT(args.length() == 2);
11604
11605 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011606 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11608 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011609 if (!maybe_check->ToObject(&check)) return maybe_check;
11610 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011611 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11612
11613 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 Handle<FixedArray> details =
11615 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011616
11617 // Thread index 0 is current thread.
11618 if (index == 0) {
11619 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 details->set(kThreadDetailsCurrentThreadIndex,
11621 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011622 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011623 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011624 } else {
11625 // Find the thread with the requested index.
11626 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 ThreadState* thread =
11628 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011629 while (index != n && thread != NULL) {
11630 thread = thread->Next();
11631 n++;
11632 }
11633 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011635 }
11636
11637 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 details->set(kThreadDetailsCurrentThreadIndex,
11639 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011640 details->set(kThreadDetailsThreadIdIndex,
11641 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011642 }
11643
11644 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011646}
11647
11648
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011649// Sets the disable break state
11650// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011651RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011652 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011653 ASSERT(args.length() == 1);
11654 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 isolate->debug()->set_disable_break(disable_break);
11656 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011657}
11658
11659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011660RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011662 ASSERT(args.length() == 1);
11663
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011664 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11665 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666 // Find the number of break points
11667 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011668 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011669 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011671 Handle<FixedArray>::cast(break_locations));
11672}
11673
11674
11675// Set a break point in a function
11676// args[0]: function
11677// args[1]: number: break source position (within the function source)
11678// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011679RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011682 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11683 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011684 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11685 RUNTIME_ASSERT(source_position >= 0);
11686 Handle<Object> break_point_object_arg = args.at<Object>(2);
11687
11688 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11690 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011691
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011692 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011693}
11694
11695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11697 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011698 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 // Iterate the heap looking for SharedFunctionInfo generated from the
11700 // script. The inner most SharedFunctionInfo containing the source position
11701 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011702 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703 // which is found is not compiled it is compiled and the heap is iterated
11704 // again as the compilation might create inner functions from the newly
11705 // compiled function and the actual requested break point might be in one of
11706 // these functions.
11707 bool done = false;
11708 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011709 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011712 { // Extra scope for iterator and no-allocation.
11713 isolate->heap()->EnsureHeapIsIterable();
11714 AssertNoAllocation no_alloc_during_heap_iteration;
11715 HeapIterator iterator;
11716 for (HeapObject* obj = iterator.next();
11717 obj != NULL; obj = iterator.next()) {
11718 if (obj->IsSharedFunctionInfo()) {
11719 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11720 if (shared->script() == *script) {
11721 // If the SharedFunctionInfo found has the requested script data and
11722 // contains the source position it is a candidate.
11723 int start_position = shared->function_token_position();
11724 if (start_position == RelocInfo::kNoPosition) {
11725 start_position = shared->start_position();
11726 }
11727 if (start_position <= position &&
11728 position <= shared->end_position()) {
11729 // If there is no candidate or this function is within the current
11730 // candidate this is the new candidate.
11731 if (target.is_null()) {
11732 target_start_position = start_position;
11733 target = shared;
11734 } else {
11735 if (target_start_position == start_position &&
11736 shared->end_position() == target->end_position()) {
11737 // If a top-level function contain only one function
11738 // declartion the source for the top-level and the
11739 // function is the same. In that case prefer the non
11740 // top-level function.
11741 if (!shared->is_toplevel()) {
11742 target_start_position = start_position;
11743 target = shared;
11744 }
11745 } else if (target_start_position <= start_position &&
11746 shared->end_position() <= target->end_position()) {
11747 // This containment check includes equality as a function
11748 // inside a top-level function can share either start or end
11749 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011750 target_start_position = start_position;
11751 target = shared;
11752 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753 }
11754 }
11755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011757 } // End for loop.
11758 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 }
11763
11764 // If the candidate found is compiled we are done. NOTE: when lazy
11765 // compilation of inner functions is introduced some additional checking
11766 // needs to be done here to compile inner functions.
11767 done = target->is_compiled();
11768 if (!done) {
11769 // If the candidate is not compiled compile it to reveal any inner
11770 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011771 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011773 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774
11775 return *target;
11776}
11777
11778
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011779// Changes the state of a break point in a script and returns source position
11780// where break point was set. NOTE: Regarding performance see the NOTE for
11781// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782// args[0]: script to set break point in
11783// args[1]: number: break source position (within the script source)
11784// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011785RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 ASSERT(args.length() == 3);
11788 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11789 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11790 RUNTIME_ASSERT(source_position >= 0);
11791 Handle<Object> break_point_object_arg = args.at<Object>(2);
11792
11793 // Get the script from the script wrapper.
11794 RUNTIME_ASSERT(wrapper->value()->IsScript());
11795 Handle<Script> script(Script::cast(wrapper->value()));
11796
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011797 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011798 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799 if (!result->IsUndefined()) {
11800 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11801 // Find position within function. The script position might be before the
11802 // source position of the first function.
11803 int position;
11804 if (shared->start_position() > source_position) {
11805 position = 0;
11806 } else {
11807 position = source_position - shared->start_position();
11808 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011809 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011810 position += shared->start_position();
11811 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011813 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814}
11815
11816
11817// Clear a break point
11818// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011819RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821 ASSERT(args.length() == 1);
11822 Handle<Object> break_point_object_arg = args.at<Object>(0);
11823
11824 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011827 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828}
11829
11830
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011831// Change the state of break on exceptions.
11832// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11833// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011834RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011837 RUNTIME_ASSERT(args[0]->IsNumber());
11838 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011840 // If the number doesn't match an enum value, the ChangeBreakOnException
11841 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 ExceptionBreakType type =
11843 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011844 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 isolate->debug()->ChangeBreakOnException(type, enable);
11846 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847}
11848
11849
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011850// Returns the state of break on exceptions
11851// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011852RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011853 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011854 ASSERT(args.length() == 1);
11855 RUNTIME_ASSERT(args[0]->IsNumber());
11856
11857 ExceptionBreakType type =
11858 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011859 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011860 return Smi::FromInt(result);
11861}
11862
11863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864// Prepare for stepping
11865// args[0]: break id for checking execution state
11866// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011867// args[2]: number of times to perform the step, for step out it is the number
11868// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011869RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871 ASSERT(args.length() == 3);
11872 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011873 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011874 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11875 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011876 if (!maybe_check->ToObject(&check)) return maybe_check;
11877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011879 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880 }
11881
11882 // Get the step action and check validity.
11883 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11884 if (step_action != StepIn &&
11885 step_action != StepNext &&
11886 step_action != StepOut &&
11887 step_action != StepInMin &&
11888 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 }
11891
11892 // Get the number of steps.
11893 int step_count = NumberToInt32(args[2]);
11894 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011895 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896 }
11897
ager@chromium.orga1645e22009-09-09 19:27:10 +000011898 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011900
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011901 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11903 step_count);
11904 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905}
11906
11907
11908// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011911 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011912 isolate->debug()->ClearStepping();
11913 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914}
11915
11916
11917// Creates a copy of the with context chain. The copy of the context chain is
11918// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011919static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11920 Handle<JSFunction> function,
11921 Handle<Context> base,
11922 JavaScriptFrame* frame,
11923 int inlined_frame_index) {
11924 HandleScope scope(isolate);
11925 List<Handle<ScopeInfo> > scope_chain;
11926 List<Handle<Context> > context_chain;
11927
11928 ScopeIterator it(isolate, frame, inlined_frame_index);
11929 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11930 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11931 ASSERT(!it.Done());
11932 scope_chain.Add(it.CurrentScopeInfo());
11933 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011934 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011935
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011936 // At the end of the chain. Return the base context to link to.
11937 Handle<Context> context = base;
11938
11939 // Iteratively copy and or materialize the nested contexts.
11940 while (!scope_chain.is_empty()) {
11941 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11942 Handle<Context> current = context_chain.RemoveLast();
11943 ASSERT(!(scope_info->HasContext() & current.is_null()));
11944
11945 if (scope_info->Type() == CATCH_SCOPE) {
11946 Handle<String> name(String::cast(current->extension()));
11947 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11948 context =
11949 isolate->factory()->NewCatchContext(function,
11950 context,
11951 name,
11952 thrown_object);
11953 } else if (scope_info->Type() == BLOCK_SCOPE) {
11954 // Materialize the contents of the block scope into a JSObject.
11955 Handle<JSObject> block_scope_object =
11956 MaterializeBlockScope(isolate, current);
11957 if (block_scope_object.is_null()) {
11958 return Handle<Context>::null();
11959 }
11960 // Allocate a new function context for the debug evaluation and set the
11961 // extension object.
11962 Handle<Context> new_context =
11963 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11964 function);
11965 new_context->set_extension(*block_scope_object);
11966 new_context->set_previous(*context);
11967 context = new_context;
11968 } else {
11969 ASSERT(scope_info->Type() == WITH_SCOPE);
11970 ASSERT(current->IsWithContext());
11971 Handle<JSObject> extension(JSObject::cast(current->extension()));
11972 context =
11973 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011974 }
erikcorry0ad885c2011-11-21 13:51:57 +000011975 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011976
11977 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978}
11979
11980
11981// Helper function to find or create the arguments object for
11982// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983static Handle<Object> GetArgumentsObject(Isolate* isolate,
11984 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011985 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011987 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988 Handle<Context> function_context) {
11989 // Try to find the value of 'arguments' to pass as parameter. If it is not
11990 // found (that is the debugged function does not reference 'arguments' and
11991 // does not support eval) then create an 'arguments' object.
11992 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011993 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011996 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011997 }
11998 }
11999
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012000 if (scope_info->HasHeapAllocatedLocals()) {
12001 VariableMode mode;
12002 InitializationFlag init_flag;
12003 index = scope_info->ContextSlotIndex(
12004 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 }
12008 }
12009
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012010 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12011
12012 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 Handle<JSObject> arguments =
12014 isolate->factory()->NewArgumentsObject(function, length);
12015 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012016
12017 AssertNoAllocation no_gc;
12018 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012020 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012021 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012022 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023 return arguments;
12024}
12025
12026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012027static const char kSourceStr[] =
12028 "(function(arguments,__source__){return eval(__source__);})";
12029
12030
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012032// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012033// extension part has all the parameters and locals of the function on the
12034// stack frame. A function which calls eval with the code to evaluate is then
12035// compiled in this context and called in this context. As this context
12036// replaces the context of the function on the stack frame a new (empty)
12037// function is created as well to be used as the closure for the context.
12038// This function and the context acts as replacements for the function on the
12039// stack frame presenting the same view of the values of parameters and
12040// local variables as if the piece of JavaScript was evaluated at the point
12041// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012042RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012044
12045 // Check the execution state and decode arguments frame and source to be
12046 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012047 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012048 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012049 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12050 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012051 if (!maybe_check_result->ToObject(&check_result)) {
12052 return maybe_check_result;
12053 }
12054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012056 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12057 CONVERT_ARG_CHECKED(String, source, 3);
12058 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12059 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012060
12061 // Handle the processing of break.
12062 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063
12064 // Get the frame where the debugging is performed.
12065 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012066 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067 JavaScriptFrame* frame = it.frame();
12068 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012069 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012070
12071 // Traverse the saved contexts chain to find the active context for the
12072 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012073 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012075 SaveContext savex(isolate);
12076 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012077
12078 // Create the (empty) function replacing the function on the stack frame for
12079 // the purpose of evaluating in the context created below. It is important
12080 // that this function does not describe any parameters and local variables
12081 // in the context. If it does then this will cause problems with the lookup
12082 // in Context::Lookup, where context slots for parameters and local variables
12083 // are looked at before the extension object.
12084 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012085 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12086 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087 go_between->set_context(function->context());
12088#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012089 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12090 ASSERT(go_between_scope_info->ParameterCount() == 0);
12091 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092#endif
12093
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012094 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012095 Handle<JSObject> local_scope = MaterializeLocalScope(
12096 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012097 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012098
12099 // Allocate a new context for the debug evaluation and set the extension
12100 // object build.
12101 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12103 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012104 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012106 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012107 Handle<Context> function_context;
12108 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012109 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012110 function_context = Handle<Context>(frame_context->declaration_context());
12111 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012112 context = CopyNestedScopeContextChain(isolate,
12113 go_between,
12114 context,
12115 frame,
12116 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012118 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012119 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012120 context =
12121 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012122 }
12123
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124 // Wrap the evaluation statement in a new function compiled in the newly
12125 // created context. The function has one parameter which has to be called
12126 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012127 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012128 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 isolate->factory()->NewStringFromAscii(
12132 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012133
12134 // Currently, the eval code will be executed in non-strict mode,
12135 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012136 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012137 Compiler::CompileEval(function_source,
12138 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012139 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012140 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012141 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012142 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012145
12146 // Invoke the result of the compilation to get the evaluation function.
12147 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149 Handle<Object> evaluation_function =
12150 Execution::Call(compiled_function, receiver, 0, NULL,
12151 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012152 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012154 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012155 frame,
12156 inlined_frame_index,
12157 function,
12158 scope_info,
12159 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160
12161 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012162 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012164 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12165 receiver,
12166 ARRAY_SIZE(argv),
12167 argv,
12168 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012169 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012170
12171 // Skip the global proxy as it has no properties and always delegates to the
12172 // real global object.
12173 if (result->IsJSGlobalProxy()) {
12174 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12175 }
12176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177 return *result;
12178}
12179
12180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012181RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183
12184 // Check the execution state and decode arguments frame and source to be
12185 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012186 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012187 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012188 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12189 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012190 if (!maybe_check_result->ToObject(&check_result)) {
12191 return maybe_check_result;
12192 }
12193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012195 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012196 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012197
12198 // Handle the processing of break.
12199 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012200
12201 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 top = top->prev();
12206 }
12207 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012208 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012209 }
12210
12211 // Get the global context now set to the top context from before the
12212 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012213 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012214
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012215 bool is_global = true;
12216
12217 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012218 // Create a new with context with the additional context information between
12219 // the context of the debugged function and the eval code to be executed.
12220 context = isolate->factory()->NewWithContext(
12221 Handle<JSFunction>(context->closure()),
12222 context,
12223 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012224 is_global = false;
12225 }
12226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012228 // Currently, the eval code will be executed in non-strict mode,
12229 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012230 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012231 Compiler::CompileEval(source,
12232 context,
12233 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012234 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012235 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012236 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 Handle<JSFunction>(
12239 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12240 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012241
12242 // Invoke the result of the compilation to get the evaluation function.
12243 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012244 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012245 Handle<Object> result =
12246 Execution::Call(compiled_function, receiver, 0, NULL,
12247 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012248 // Clear the oneshot breakpoints so that the debugger does not step further.
12249 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012250 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 return *result;
12252}
12253
12254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012255RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012256 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012257 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261
12262 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012263 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012264 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12265 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12266 // because using
12267 // instances->set(i, *GetScriptWrapper(script))
12268 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12269 // already have deferenced the instances handle.
12270 Handle<JSValue> wrapper = GetScriptWrapper(script);
12271 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 }
12273
12274 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012275 Handle<JSObject> result =
12276 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012277 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012278 return *result;
12279}
12280
12281
12282// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012283static int DebugReferencedBy(HeapIterator* iterator,
12284 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012285 Object* instance_filter, int max_references,
12286 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287 JSFunction* arguments_function) {
12288 NoHandleAllocation ha;
12289 AssertNoAllocation no_alloc;
12290
12291 // Iterate the heap.
12292 int count = 0;
12293 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012294 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012295 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296 (max_references == 0 || count < max_references)) {
12297 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012298 if (heap_obj->IsJSObject()) {
12299 // Skip context extension objects and argument arrays as these are
12300 // checked in the context of functions using them.
12301 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012302 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012303 obj->map()->constructor() == arguments_function) {
12304 continue;
12305 }
12306
12307 // Check if the JS object has a reference to the object looked for.
12308 if (obj->ReferencesObject(target)) {
12309 // Check instance filter if supplied. This is normally used to avoid
12310 // references from mirror objects (see Runtime_IsInPrototypeChain).
12311 if (!instance_filter->IsUndefined()) {
12312 Object* V = obj;
12313 while (true) {
12314 Object* prototype = V->GetPrototype();
12315 if (prototype->IsNull()) {
12316 break;
12317 }
12318 if (instance_filter == prototype) {
12319 obj = NULL; // Don't add this object.
12320 break;
12321 }
12322 V = prototype;
12323 }
12324 }
12325
12326 if (obj != NULL) {
12327 // Valid reference found add to instance array if supplied an update
12328 // count.
12329 if (instances != NULL && count < instances_size) {
12330 instances->set(count, obj);
12331 }
12332 last = obj;
12333 count++;
12334 }
12335 }
12336 }
12337 }
12338
12339 // Check for circular reference only. This can happen when the object is only
12340 // referenced from mirrors and has a circular reference in which case the
12341 // object is not really alive and would have been garbage collected if not
12342 // referenced from the mirror.
12343 if (count == 1 && last == target) {
12344 count = 0;
12345 }
12346
12347 // Return the number of referencing objects found.
12348 return count;
12349}
12350
12351
12352// Scan the heap for objects with direct references to an object
12353// args[0]: the object to find references to
12354// args[1]: constructor function for instances to exclude (Mirror)
12355// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012356RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012357 ASSERT(args.length() == 3);
12358
12359 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012360 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12361 // The heap iterator reserves the right to do a GC to make the heap iterable.
12362 // Due to the GC above we know it won't need to do that, but it seems cleaner
12363 // to get the heap iterator constructed before we start having unprotected
12364 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012365
12366 // Check parameters.
12367 CONVERT_CHECKED(JSObject, target, args[0]);
12368 Object* instance_filter = args[1];
12369 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12370 instance_filter->IsJSObject());
12371 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12372 RUNTIME_ASSERT(max_references >= 0);
12373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012376 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012377 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378 JSFunction* arguments_function =
12379 JSFunction::cast(arguments_boilerplate->map()->constructor());
12380
12381 // Get the number of referencing objects.
12382 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012383 HeapIterator heap_iterator;
12384 count = DebugReferencedBy(&heap_iterator,
12385 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012386 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387
12388 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012389 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012390 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012391 if (!maybe_object->ToObject(&object)) return maybe_object;
12392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012393 FixedArray* instances = FixedArray::cast(object);
12394
12395 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012396 // AllocateFixedArray above does not make the heap non-iterable.
12397 ASSERT(HEAP->IsHeapIterable());
12398 HeapIterator heap_iterator2;
12399 count = DebugReferencedBy(&heap_iterator2,
12400 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012401 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402
12403 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012404 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012405 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012406 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012407 if (!maybe_result->ToObject(&result)) return maybe_result;
12408 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012409}
12410
12411
12412// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012413static int DebugConstructedBy(HeapIterator* iterator,
12414 JSFunction* constructor,
12415 int max_references,
12416 FixedArray* instances,
12417 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012418 AssertNoAllocation no_alloc;
12419
12420 // Iterate the heap.
12421 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012422 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012423 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 (max_references == 0 || count < max_references)) {
12425 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012426 if (heap_obj->IsJSObject()) {
12427 JSObject* obj = JSObject::cast(heap_obj);
12428 if (obj->map()->constructor() == constructor) {
12429 // Valid reference found add to instance array if supplied an update
12430 // count.
12431 if (instances != NULL && count < instances_size) {
12432 instances->set(count, obj);
12433 }
12434 count++;
12435 }
12436 }
12437 }
12438
12439 // Return the number of referencing objects found.
12440 return count;
12441}
12442
12443
12444// Scan the heap for objects constructed by a specific function.
12445// args[0]: the constructor to find instances of
12446// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012447RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 ASSERT(args.length() == 2);
12449
12450 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012451 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012452
12453 // Check parameters.
12454 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12455 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12456 RUNTIME_ASSERT(max_references >= 0);
12457
12458 // Get the number of referencing objects.
12459 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012460 HeapIterator heap_iterator;
12461 count = DebugConstructedBy(&heap_iterator,
12462 constructor,
12463 max_references,
12464 NULL,
12465 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012466
12467 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012468 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012469 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012470 if (!maybe_object->ToObject(&object)) return maybe_object;
12471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 FixedArray* instances = FixedArray::cast(object);
12473
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012474 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012475 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012476 HeapIterator heap_iterator2;
12477 count = DebugConstructedBy(&heap_iterator2,
12478 constructor,
12479 max_references,
12480 instances,
12481 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482
12483 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012484 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012485 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12486 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012487 if (!maybe_result->ToObject(&result)) return maybe_result;
12488 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012489 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490}
12491
12492
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012493// Find the effective prototype object as returned by __proto__.
12494// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012495RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012496 ASSERT(args.length() == 1);
12497
12498 CONVERT_CHECKED(JSObject, obj, args[0]);
12499
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012500 // Use the __proto__ accessor.
12501 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502}
12503
12504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012505RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012506 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012508 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012509}
12510
12511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012512RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012513#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012514 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012515 ASSERT(args.length() == 1);
12516 // Get the function and make sure it is compiled.
12517 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012518 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012519 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012520 return Failure::Exception();
12521 }
12522 func->code()->PrintLn();
12523#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012525}
ager@chromium.org9085a012009-05-11 19:22:57 +000012526
12527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012528RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012529#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012530 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012531 ASSERT(args.length() == 1);
12532 // Get the function and make sure it is compiled.
12533 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012534 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012535 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012536 return Failure::Exception();
12537 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012538 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012539#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012541}
12542
12543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012544RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012545 NoHandleAllocation ha;
12546 ASSERT(args.length() == 1);
12547
12548 CONVERT_CHECKED(JSFunction, f, args[0]);
12549 return f->shared()->inferred_name();
12550}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012551
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012553static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12554 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012556 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012557 int counter = 0;
12558 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012559 for (HeapObject* obj = iterator->next();
12560 obj != NULL;
12561 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012562 ASSERT(obj != NULL);
12563 if (!obj->IsSharedFunctionInfo()) {
12564 continue;
12565 }
12566 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12567 if (shared->script() != script) {
12568 continue;
12569 }
12570 if (counter < buffer_size) {
12571 buffer->set(counter, shared);
12572 }
12573 counter++;
12574 }
12575 return counter;
12576}
12577
12578// For a script finds all SharedFunctionInfo's in the heap that points
12579// to this script. Returns JSArray of SharedFunctionInfo wrapped
12580// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012581RUNTIME_FUNCTION(MaybeObject*,
12582 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012583 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012584 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012585 CONVERT_CHECKED(JSValue, script_value, args[0]);
12586
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012588 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12589
12590 const int kBufferSize = 32;
12591
12592 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012593 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012594 int number;
12595 {
12596 isolate->heap()->EnsureHeapIsIterable();
12597 AssertNoAllocation no_allocations;
12598 HeapIterator heap_iterator;
12599 Script* scr = *script;
12600 FixedArray* arr = *array;
12601 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12602 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012603 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012605 isolate->heap()->EnsureHeapIsIterable();
12606 AssertNoAllocation no_allocations;
12607 HeapIterator heap_iterator;
12608 Script* scr = *script;
12609 FixedArray* arr = *array;
12610 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012611 }
12612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012614 result->set_length(Smi::FromInt(number));
12615
12616 LiveEdit::WrapSharedFunctionInfos(result);
12617
12618 return *result;
12619}
12620
12621// For a script calculates compilation information about all its functions.
12622// The script source is explicitly specified by the second argument.
12623// The source of the actual script is not used, however it is important that
12624// all generated code keeps references to this particular instance of script.
12625// Returns a JSArray of compilation infos. The array is ordered so that
12626// each function with all its descendant is always stored in a continues range
12627// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012628RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012629 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012630 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012631 CONVERT_CHECKED(JSValue, script, args[0]);
12632 CONVERT_ARG_CHECKED(String, source, 1);
12633 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12634
12635 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12636
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012638 return Failure::Exception();
12639 }
12640
12641 return result;
12642}
12643
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012644// Changes the source of the script to a new_source.
12645// If old_script_name is provided (i.e. is a String), also creates a copy of
12646// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012647RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012650 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12651 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012652 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012653
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012654 CONVERT_CHECKED(Script, original_script_pointer,
12655 original_script_value->value());
12656 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012657
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012658 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12659 new_source,
12660 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012661
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012662 if (old_script->IsScript()) {
12663 Handle<Script> script_handle(Script::cast(old_script));
12664 return *(GetScriptWrapper(script_handle));
12665 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012666 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012667 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012668}
12669
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012671RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012672 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012673 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012674 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12675 return LiveEdit::FunctionSourceUpdated(shared_info);
12676}
12677
12678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012679// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012680RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012681 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012682 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012683 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12684 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12685
ager@chromium.orgac091b72010-05-05 07:34:42 +000012686 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012687}
12688
12689// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012690RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012691 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 HandleScope scope(isolate);
12693 Handle<Object> function_object(args[0], isolate);
12694 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012695
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012696 if (function_object->IsJSValue()) {
12697 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12698 if (script_object->IsJSValue()) {
12699 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012700 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012701 }
12702
12703 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12704 } else {
12705 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12706 // and we check it in this function.
12707 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012708
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012709 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012710}
12711
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012712
12713// In a code of a parent function replaces original function as embedded object
12714// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012715RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012716 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012717 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718
12719 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12720 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12721 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12722
12723 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12724 subst_wrapper);
12725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012726 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012727}
12728
12729
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012730// Updates positions of a shared function info (first parameter) according
12731// to script source change. Text change is described in second parameter as
12732// array of groups of 3 numbers:
12733// (change_begin, change_end, change_end_new_position).
12734// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012735RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012736 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012737 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012738 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12739 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12740
ager@chromium.orgac091b72010-05-05 07:34:42 +000012741 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012742}
12743
12744
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012745// For array of SharedFunctionInfo's (each wrapped in JSValue)
12746// checks that none of them have activations on stacks (of any thread).
12747// Returns array of the same length with corresponding results of
12748// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012750 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012751 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012752 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012753 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012754
ager@chromium.org357bf652010-04-12 11:30:10 +000012755 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012756}
12757
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012758// Compares 2 strings line-by-line, then token-wise and returns diff in form
12759// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12760// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012761RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012762 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012763 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012764 CONVERT_ARG_CHECKED(String, s1, 0);
12765 CONVERT_ARG_CHECKED(String, s2, 1);
12766
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012767 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012768}
12769
12770
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012771// A testing entry. Returns statement position which is the closest to
12772// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012773RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012774 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012776 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12777 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012780
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012781 if (code->kind() != Code::FUNCTION &&
12782 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012784 }
12785
12786 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012787 int closest_pc = 0;
12788 int distance = kMaxInt;
12789 while (!it.done()) {
12790 int statement_position = static_cast<int>(it.rinfo()->data());
12791 // Check if this break point is closer that what was previously found.
12792 if (source_position <= statement_position &&
12793 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012794 closest_pc =
12795 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012796 distance = statement_position - source_position;
12797 // Check whether we can't get any closer.
12798 if (distance == 0) break;
12799 }
12800 it.next();
12801 }
12802
12803 return Smi::FromInt(closest_pc);
12804}
12805
12806
ager@chromium.org357bf652010-04-12 11:30:10 +000012807// Calls specified function with or without entering the debugger.
12808// This is used in unit tests to run code as if debugger is entered or simply
12809// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012810RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012811 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012812 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012813 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12814 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12815
12816 Handle<Object> result;
12817 bool pending_exception;
12818 {
12819 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012820 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012821 &pending_exception);
12822 } else {
12823 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012824 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012825 &pending_exception);
12826 }
12827 }
12828 if (!pending_exception) {
12829 return *result;
12830 } else {
12831 return Failure::Exception();
12832 }
12833}
12834
12835
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012836// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012837RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012838 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012839 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012840 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12841 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012843}
12844
12845
12846// Performs a GC.
12847// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012848RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 isolate->heap()->CollectAllGarbage(true);
12850 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012851}
12852
12853
12854// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012855RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012856 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012857 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012859 }
12860 return Smi::FromInt(usage);
12861}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012862
12863
12864// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012866#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012867 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012868#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012870#endif
12871}
12872
12873
12874// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012875RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012876#ifdef LIVE_OBJECT_LIST
12877 return LiveObjectList::Capture();
12878#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012880#endif
12881}
12882
12883
12884// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012885RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012886#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012887 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012888 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012889 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012890#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012892#endif
12893}
12894
12895
12896// Generates the response to a debugger request for a dump of the objects
12897// contained in the difference between the captured live object lists
12898// specified by id1 and id2.
12899// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12900// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012901RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902#ifdef LIVE_OBJECT_LIST
12903 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012904 CONVERT_SMI_ARG_CHECKED(id1, 0);
12905 CONVERT_SMI_ARG_CHECKED(id2, 1);
12906 CONVERT_SMI_ARG_CHECKED(start, 2);
12907 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012908 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12909 EnterDebugger enter_debugger;
12910 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12911#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012912 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012913#endif
12914}
12915
12916
12917// Gets the specified object as requested by the debugger.
12918// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012919RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012920#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012921 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012922 Object* result = LiveObjectList::GetObj(obj_id);
12923 return result;
12924#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012925 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012926#endif
12927}
12928
12929
12930// Gets the obj id for the specified address if valid.
12931// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012932RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012933#ifdef LIVE_OBJECT_LIST
12934 HandleScope scope;
12935 CONVERT_ARG_CHECKED(String, address, 0);
12936 Object* result = LiveObjectList::GetObjId(address);
12937 return result;
12938#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012939 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012940#endif
12941}
12942
12943
12944// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012945RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012946#ifdef LIVE_OBJECT_LIST
12947 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012948 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012949 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12950 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12951 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12952 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12953 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12954
12955 Handle<JSObject> instance_filter;
12956 if (args[1]->IsJSObject()) {
12957 instance_filter = args.at<JSObject>(1);
12958 }
12959 bool verbose = false;
12960 if (args[2]->IsBoolean()) {
12961 verbose = args[2]->IsTrue();
12962 }
12963 int start = 0;
12964 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012965 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966 }
12967 int limit = Smi::kMaxValue;
12968 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012969 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012970 }
12971
12972 return LiveObjectList::GetObjRetainers(obj_id,
12973 instance_filter,
12974 verbose,
12975 start,
12976 limit,
12977 filter_obj);
12978#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012979 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980#endif
12981}
12982
12983
12984// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012985RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012986#ifdef LIVE_OBJECT_LIST
12987 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012988 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12989 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12991
12992 Handle<JSObject> instance_filter;
12993 if (args[2]->IsJSObject()) {
12994 instance_filter = args.at<JSObject>(2);
12995 }
12996
12997 Object* result =
12998 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12999 return result;
13000#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013001 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013002#endif
13003}
13004
13005
13006// Generates the response to a debugger request for a list of all
13007// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013008RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013009#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013010 CONVERT_SMI_ARG_CHECKED(start, 0);
13011 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012 return LiveObjectList::Info(start, count);
13013#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013014 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013015#endif
13016}
13017
13018
13019// Gets a dump of the specified object as requested by the debugger.
13020// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013021RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013022#ifdef LIVE_OBJECT_LIST
13023 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013024 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025 Object* result = LiveObjectList::PrintObj(obj_id);
13026 return result;
13027#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013028 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013029#endif
13030}
13031
13032
13033// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013034RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013035#ifdef LIVE_OBJECT_LIST
13036 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013037 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013038#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013039 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013040#endif
13041}
13042
13043
13044// Generates the response to a debugger request for a summary of the types
13045// of objects in the difference between the captured live object lists
13046// specified by id1 and id2.
13047// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13048// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013049RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013050#ifdef LIVE_OBJECT_LIST
13051 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013052 CONVERT_SMI_ARG_CHECKED(id1, 0);
13053 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013054 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13055
13056 EnterDebugger enter_debugger;
13057 return LiveObjectList::Summarize(id1, id2, filter_obj);
13058#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013059 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060#endif
13061}
13062
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013063#endif // ENABLE_DEBUGGER_SUPPORT
13064
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013066RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013067 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013068 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013070}
13071
13072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013073RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013074 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013075 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013076 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013077}
13078
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013080// Finds the script object from the script data. NOTE: This operation uses
13081// heap traversal to find the function generated for the source position
13082// for the requested break point. For lazily compiled functions several heap
13083// traversals might be required rendering this operation as a rather slow
13084// operation. However for setting break points which is normally done through
13085// some kind of user interaction the performance is not crucial.
13086static Handle<Object> Runtime_GetScriptFromScriptName(
13087 Handle<String> script_name) {
13088 // Scan the heap for Script objects to find the script with the requested
13089 // script data.
13090 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013091 script_name->GetHeap()->EnsureHeapIsIterable();
13092 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013093 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013094 HeapObject* obj = NULL;
13095 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013096 // If a script is found check if it has the script data requested.
13097 if (obj->IsScript()) {
13098 if (Script::cast(obj)->name()->IsString()) {
13099 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13100 script = Handle<Script>(Script::cast(obj));
13101 }
13102 }
13103 }
13104 }
13105
13106 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013107 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013108
13109 // Return the script found.
13110 return GetScriptWrapper(script);
13111}
13112
13113
13114// Get the script object from script data. NOTE: Regarding performance
13115// see the NOTE for GetScriptFromScriptData.
13116// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013117RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013118 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013119
13120 ASSERT(args.length() == 1);
13121
13122 CONVERT_CHECKED(String, script_name, args[0]);
13123
13124 // Find the requested script.
13125 Handle<Object> result =
13126 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13127 return *result;
13128}
13129
13130
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013131// Determines whether the given stack frame should be displayed in
13132// a stack trace. The caller is the error constructor that asked
13133// for the stack trace to be collected. The first time a construct
13134// call to this function is encountered it is skipped. The seen_caller
13135// in/out parameter is used to remember if the caller has been seen
13136// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013137static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13138 Object* caller,
13139 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013140 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013141 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013142 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013143 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013144 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13145 Object* raw_fun = frame->function();
13146 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013147 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013148 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013149 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013150 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013151 *seen_caller = true;
13152 return false;
13153 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013154 // Skip all frames until we've seen the caller.
13155 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013156 // Also, skip non-visible built-in functions and any call with the builtins
13157 // object as receiver, so as to not reveal either the builtins object or
13158 // an internal function.
13159 // The --builtins-in-stack-traces command line flag allows including
13160 // internal call sites in the stack trace for debugging purposes.
13161 if (!FLAG_builtins_in_stack_traces) {
13162 JSFunction* fun = JSFunction::cast(raw_fun);
13163 if (frame->receiver()->IsJSBuiltinsObject() ||
13164 (fun->IsBuiltin() && !fun->shared()->native())) {
13165 return false;
13166 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013167 }
13168 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013169}
13170
13171
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013172// Collect the raw data for a stack trace. Returns an array of 4
13173// element segments each containing a receiver, function, code and
13174// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013175RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013176 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013177 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013178 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013180 HandleScope scope(isolate);
13181 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013182
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013183 limit = Max(limit, 0); // Ensure that limit is not negative.
13184 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013185 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013186 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013187
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013188 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013189 // If the caller parameter is a function we skip frames until we're
13190 // under it before starting to collect.
13191 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013192 int cursor = 0;
13193 int frames_seen = 0;
13194 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013195 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013196 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013197 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013198 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013199 // Set initial size to the maximum inlining level + 1 for the outermost
13200 // function.
13201 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013202 frame->Summarize(&frames);
13203 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013204 if (cursor + 4 > elements->length()) {
13205 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13206 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013207 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013208 for (int i = 0; i < cursor; i++) {
13209 new_elements->set(i, elements->get(i));
13210 }
13211 elements = new_elements;
13212 }
13213 ASSERT(cursor + 4 <= elements->length());
13214
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013215 Handle<Object> recv = frames[i].receiver();
13216 Handle<JSFunction> fun = frames[i].function();
13217 Handle<Code> code = frames[i].code();
13218 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013219 elements->set(cursor++, *recv);
13220 elements->set(cursor++, *fun);
13221 elements->set(cursor++, *code);
13222 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013223 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013224 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013225 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013227 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013228 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013229 return *result;
13230}
13231
13232
ager@chromium.org3811b432009-10-28 14:53:37 +000013233// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013234RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013235 ASSERT_EQ(args.length(), 0);
13236
13237 NoHandleAllocation ha;
13238
13239 const char* version_string = v8::V8::GetVersion();
13240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013241 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13242 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013243}
13244
13245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013246RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013247 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013248 OS::PrintError("abort: %s\n",
13249 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013250 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013251 OS::Abort();
13252 UNREACHABLE();
13253 return NULL;
13254}
13255
13256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013258 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013259 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013260 Object* key = args[1];
13261
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013262 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013263 Object* o = cache->get(finger_index);
13264 if (o == key) {
13265 // The fastest case: hit the same place again.
13266 return cache->get(finger_index + 1);
13267 }
13268
13269 for (int i = finger_index - 2;
13270 i >= JSFunctionResultCache::kEntriesIndex;
13271 i -= 2) {
13272 o = cache->get(i);
13273 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013274 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013275 return cache->get(i + 1);
13276 }
13277 }
13278
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013279 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013280 ASSERT(size <= cache->length());
13281
13282 for (int i = size - 2; i > finger_index; i -= 2) {
13283 o = cache->get(i);
13284 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013285 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013286 return cache->get(i + 1);
13287 }
13288 }
13289
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013290 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013291 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013292
13293 Handle<JSFunctionResultCache> cache_handle(cache);
13294 Handle<Object> key_handle(key);
13295 Handle<Object> value;
13296 {
13297 Handle<JSFunction> factory(JSFunction::cast(
13298 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13299 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013300 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013301 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013302 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013303 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013304 value = Execution::Call(factory,
13305 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013306 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013307 argv,
13308 &pending_exception);
13309 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013310 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013311
13312#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013313 if (FLAG_verify_heap) {
13314 cache_handle->JSFunctionResultCacheVerify();
13315 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013316#endif
13317
13318 // Function invocation may have cleared the cache. Reread all the data.
13319 finger_index = cache_handle->finger_index();
13320 size = cache_handle->size();
13321
13322 // If we have spare room, put new data into it, otherwise evict post finger
13323 // entry which is likely to be the least recently used.
13324 int index = -1;
13325 if (size < cache_handle->length()) {
13326 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13327 index = size;
13328 } else {
13329 index = finger_index + JSFunctionResultCache::kEntrySize;
13330 if (index == cache_handle->length()) {
13331 index = JSFunctionResultCache::kEntriesIndex;
13332 }
13333 }
13334
13335 ASSERT(index % 2 == 0);
13336 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13337 ASSERT(index < cache_handle->length());
13338
13339 cache_handle->set(index, *key_handle);
13340 cache_handle->set(index + 1, *value);
13341 cache_handle->set_finger_index(index);
13342
13343#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013344 if (FLAG_verify_heap) {
13345 cache_handle->JSFunctionResultCacheVerify();
13346 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013347#endif
13348
13349 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013350}
13351
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013353RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013354 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013355 CONVERT_ARG_CHECKED(String, type, 0);
13356 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013357 return *isolate->factory()->NewJSMessageObject(
13358 type,
13359 arguments,
13360 0,
13361 0,
13362 isolate->factory()->undefined_value(),
13363 isolate->factory()->undefined_value(),
13364 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013365}
13366
13367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013368RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013369 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13370 return message->type();
13371}
13372
13373
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013374RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013375 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13376 return message->arguments();
13377}
13378
13379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013380RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013381 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13382 return Smi::FromInt(message->start_position());
13383}
13384
13385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013386RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013387 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13388 return message->script();
13389}
13390
13391
kasper.lund44510672008-07-25 07:37:58 +000013392#ifdef DEBUG
13393// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13394// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013395RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013396 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013397 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013398#define COUNT_ENTRY(Name, argc, ressize) + 1
13399 int entry_count = 0
13400 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13401 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13402 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13403#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013404 Factory* factory = isolate->factory();
13405 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013406 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013407 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013408#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013409 { \
13410 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013411 Handle<String> name; \
13412 /* Inline runtime functions have an underscore in front of the name. */ \
13413 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013414 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013415 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13416 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013417 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013418 Vector<const char>(#Name, StrLength(#Name))); \
13419 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013420 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013421 pair_elements->set(0, *name); \
13422 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013423 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013424 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013425 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013426 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013427 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013428 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013429 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013430 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013431#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013432 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013433 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013434 return *result;
13435}
kasper.lund44510672008-07-25 07:37:58 +000013436#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013437
13438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013439RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013440 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013441 CONVERT_CHECKED(String, format, args[0]);
13442 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013443 String::FlatContent format_content = format->GetFlatContent();
13444 RUNTIME_ASSERT(format_content.IsAscii());
13445 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013446 LOGGER->LogRuntime(chars, elms);
13447 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013448}
13449
13450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013451RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013452 UNREACHABLE(); // implemented as macro in the parser
13453 return NULL;
13454}
13455
13456
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013457#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13458 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13459 CONVERT_CHECKED(JSObject, obj, args[0]); \
13460 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13461 }
13462
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013463ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013464ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13465ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13466ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13467ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13468ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13469ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13470ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13471ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13472ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13473ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13474ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13475ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13476ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13477
13478#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13479
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013480
13481RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13482 ASSERT(args.length() == 2);
13483 CONVERT_CHECKED(JSObject, obj1, args[0]);
13484 CONVERT_CHECKED(JSObject, obj2, args[1]);
13485 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13486}
13487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013488// ----------------------------------------------------------------------------
13489// Implementation of Runtime
13490
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013491#define F(name, number_of_args, result_size) \
13492 { Runtime::k##name, Runtime::RUNTIME, #name, \
13493 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013494
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013495
13496#define I(name, number_of_args, result_size) \
13497 { Runtime::kInline##name, Runtime::INLINE, \
13498 "_" #name, NULL, number_of_args, result_size },
13499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013500static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013501 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013502 INLINE_FUNCTION_LIST(I)
13503 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013504};
13505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013507MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13508 Object* dictionary) {
13509 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013510 ASSERT(dictionary != NULL);
13511 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13512 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013513 Object* name_symbol;
13514 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013515 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013516 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13517 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013518 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013519 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13520 String::cast(name_symbol),
13521 Smi::FromInt(i),
13522 PropertyDetails(NONE, NORMAL));
13523 if (!maybe_dictionary->ToObject(&dictionary)) {
13524 // Non-recoverable failure. Calling code must restart heap
13525 // initialization.
13526 return maybe_dictionary;
13527 }
13528 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013529 }
13530 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013531}
13532
13533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013534const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13535 Heap* heap = name->GetHeap();
13536 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013537 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013538 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013539 int function_index = Smi::cast(smi_index)->value();
13540 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013541 }
13542 return NULL;
13543}
13544
13545
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013546const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013547 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13548}
13549
13550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013551void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013552 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013553 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013554 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013555 if (isolate->heap()->new_space()->AddFreshPage()) {
13556 return;
13557 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013558 // Try to do a garbage collection; ignore it if it fails. The C
13559 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013560 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013561 } else {
13562 // Handle last resort GC and make sure to allow future allocations
13563 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013564 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013565 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013567}
13568
13569
13570} } // namespace v8::internal